# templates

name: AI Email Analyzer: Process PDFs, Images & Save to Google Drive + Telegram
author_name: Davide
author_username: n3witalia
categories: []
created_at: 2025-03-14T16:27:15.934Z
updated_at: 2025-03-14T16:27:15.934Z
url: https://n8n.io/workflows/3169
scraped_at: 2025-06-19 22:50:08
description:
  This workflow automates the process of analyzing emails and their attachments (PDFs and images) using AI models (DeepSeek, Gemini, and OpenRouter). It extracts and summarizes the content of emails and attachments, saves the summaries to Google Sheets, and sends a final consolidated summary via Telegram. 

  This is a powerful tool for automating email analysis and summarization, saving time and ensuring that important information is easily accessible and actionable.

  Below is a breakdown of the workflow:

  1. How It Works
  The workflow is designed to process incoming emails, analyze their content and attachments, and generate summaries. Here's how it works:

  Email Trigger:
     The workflow starts with the Email Trigger (IMAP) node, which monitors an email inbox for new emails.
     If an email contains attachments, the workflow processes them.

  Check for Attachments:
     The Contain Attachments? node checks if the email has attachments.
     If attachments are present, the workflow proceeds to process them.

  Process Attachments:
     The Get PDF and Images Attachments node extracts PDF and image attachments from the email.
     The Switch node separates PDFs and images for further processing:
       PDFs: The Extract from PDF node extracts text from PDFs, and the PDF Analyzer node summarizes the content.
       Images: The Analyze Image node uses AI to describe the content of images.

  Summarize Email Content:
     The Convert Text node converts the email's HTML content to plain text.
     The Email Summarization Chain node uses AI to generate a summary of the email's text content.

  Save Summaries:
     The Save Summary PDF, Save Summary Image, and Save Summary Text nodes save the summaries of PDFs, images, and email text, respectively, to Google Sheets.

  Consolidate Summaries:
     The All Summaries node aggregates the summaries of the email text, PDFs, and images.
     The Create Final Summary node uses AI to generate a unified summary of all the content.

  Send Final Summary:
     The Send Final Summary node sends the consolidated summary via Telegram to a specified chat ID.

  2. Set Up Steps
  To set up and use this workflow in n8n, follow these steps:

  IMAP Configuration:
     Set up IMAP credentials in n8n for the Email Trigger (IMAP) node.
     Ensure the email account is accessible via IMAP.

  AI Model Configuration:
     Configure the DeepSeek, Gemini, and OpenRouter credentials in n8n for the Email Summarization Chain, PDF Analyzer, and Create Final Summary nodes.
     Ensure the AI models are set up to generate summaries.

  Google Sheets Integration:
     Set up Google Sheets credentials in n8n for the Save Summary PDF, Save Summary Image, and Save Summary Text nodes.
     Specify the Google Sheet and worksheet where the summaries will be saved.

  Telegram Integration:
     Set up Telegram credentials in n8n for the Send Final Summary node.
     Insert your Chat ID in the Telegram node to receive the final summary.

  Test the Workflow:
     Send an email with attachments (PDFs and images) to the monitored email account.
     The workflow will:
       Extract and summarize the email content and attachments.
       Save the summaries to Google Sheets.
       Send a consolidated summary via Telegram.

  Optional Customization:
       replace IMAP trigger with Gmail or Outlook trigger 
       Modify the workflow to include additional features, such as:
       Adding more AI models for different types of analysis.
       Sending notifications via other channels (e.g., Slack, email).
       Integrating with other storage services (e.g., Dropbox, AWS S3).

  Need help customizing?  
  Contact me for consulting and support or add me on Linkedin. 

nodes_used:
  ["n8n-nodes-base.googleSheets","n8n-nodes-base.telegram","n8n-nodes-base.googleDrive","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.chainSummarization","@n8n/n8n-nodes-langchain.chainLlm","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.outputParserStructured","@n8n/n8n-nodes-langchain.openAi","@n8n/n8n-nodes-langchain.lmChatOpenRouter"]

workflow_json:
  {"id":"MCzA5RzvO83kNJi7","meta":{"instanceId":"a4bfc93e975ca233ac45ed7c9227d84cf5a2329310525917adaf3312e10d5462","templateCredsSetupCompleted":true},"name":"AI Email Analyzer: Process PDFs, Images","tags":[],"nodes":[{"id":"0526c603-2c35-4f65-88ee-e143f7aa3ca4","name":"Email Trigger (IMAP)","type":"n8n-nodes-base.emailReadImap","position":[-80,500],"parameters":{"options":{},"downloadAttachments":true},"credentials":{"imap":{"id":"k31W9oGddl9pMDy4","name":"IMAP info@n3witalia.com"}},"typeVersion":2},{"id":"9b0b83d1-7d7c-4858-aedc-4816e2f02276","name":"DeepSeek R1","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[1320,980],"parameters":{"model":{"__rl":true,"mode":"list","value":"deepseek/deepseek-r1:free","cachedResultName":"deepseek/deepseek-r1:free"},"options":{}},"credentials":{"openAiApi":{"id":"XJTqRiKFJpFs5MuX","name":"OpenRouter account"}},"typeVersion":1.2},{"id":"2e8ad64a-d767-441e-9e12-7a75f5ed4c1c","name":"Email Summarization Chain","type":"@n8n/n8n-nodes-langchain.chainSummarization","position":[1360,800],"parameters":{"options":{"binaryDataKey":"={{ $json.data }}","summarizationMethodAndPrompts":{"values":{"prompt":"=Write a concise summary of the following in max 100 words :\n\n\"{{ $json.data }}\"\n\nDo not enter the total number of words used.","combineMapPrompt":"=## Email Summarization System Prompt\n\nYou are a specialized AI assistant focused exclusively on creating precise, concise summaries of emails. Your task is to analyze the complete email text provided as input and produce a clear, comprehensive summary that captures all essential information in a cohesive narrative format.\n\n### Your responsibilities:\n\n1. Extract and summarize the main topic and purpose of the email\n2. Identify key points, requests, deadlines, or action items mentioned\n3. Preserve critical details like dates, times, locations, and names\n4. Maintain the original tone and urgency level of the message\n5. Organize information in order of importance\n6. Remove unnecessary pleasantries, redundancies, and filler content\n\n### Summary format:\n\n- Begin with a one-sentence overview of the email's main purpose\n- Present all key information in a cohesive paragraph format (no bullet points)\n- Follow a logical flow from most to least important information\n- Include any critical deadlines, requests, or action items within the narrative\n- Keep the summary to 3-5 sentences total\n- Use clear, straightforward language with appropriate transitions between ideas\n- Preserve the original intent and meaning without introducing new information\n\n### What to exclude:\n\n- Greetings and sign-offs\n- Redundant information\n- Minor details that don't affect the main message\n- Your own opinions or interpretations\n- Information not explicitly stated in the email\n\nThe email text to summarize is:\n{{$json.data}}"}}},"operationMode":"nodeInputBinary"},"typeVersion":2},{"id":"97f2b5f8-b2ba-4bd5-a951-c97e64e6f833","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-140,-280],"parameters":{"color":3,"width":580,"height":400,"content":"# AI Email Analyzer: Process PDFs, Images \n\nThis is a powerful tool for automating email analysis and summarization, saving time and ensuring that important information is easily accessible and actionable.\n\nAll summaries are saved on a Google Sheet and identified by a numeric ID referring to the single email.\n\n## Preliminary step:\n- Clone this [Google Drive Sheet](https://docs.google.com/spreadsheets/d/1rBa0RI6XFfMerylVCV0dlKhJT_f4UAd8S6jyYX4aRRo/edit?usp=sharing)\n- Insert  your Chat_ID in Telegram node\n- Choose the AI model you prefer\n"},"typeVersion":1},{"id":"d2012cbc-0e79-4579-ac3d-e5e84ad56dc1","name":"Switch","type":"n8n-nodes-base.switch","position":[960,120],"parameters":{"rules":{"values":[{"outputKey":"pdf","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"and","conditions":[{"id":"31b7fb0b-3149-479e-852a-52c1ec8935ca","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $binary.data.fileExtension }}","rightValue":"pdf"}]},"renameOutput":true},{"outputKey":"image","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"and","conditions":[{"id":"9fe6411d-cf35-4fdd-a9ad-8c96f0a5cf66","operator":{"type":"string","operation":"regex"},"leftValue":"={{ $binary.data.fileExtension }}","rightValue":"=/^(jpg|png)$/i"}]},"renameOutput":true}]},"options":{},"looseTypeValidation":true},"typeVersion":3.2},{"id":"8a9d55b8-9ba5-4a6f-ae13-9c529875a2a4","name":"Structured Output Parser","type":"@n8n/n8n-nodes-langchain.outputParserStructured","position":[2040,-320],"parameters":{"schemaType":"manual","inputSchema":"{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"content\": {\n\t\t\t\"type\": \"string\"\n\t\t}\n\t}\n}"},"typeVersion":1.2},{"id":"658696f5-08e0-4d51-89bc-2a1c31576700","name":"Split Out","type":"n8n-nodes-base.splitOut","position":[2540,-420],"parameters":{"options":{},"fieldToSplitOut":"=output"},"typeVersion":1},{"id":"d2ba57c3-9e0e-4a7d-957d-216763e357c3","name":"Aggregate","type":"n8n-nodes-base.aggregate","position":[3660,220],"parameters":{"options":{},"fieldsToAggregate":{"fieldToAggregate":[{"fieldToAggregate":"data.output"}]}},"typeVersion":1},{"id":"10e6d3c6-10f6-4fea-be37-b5ee50e0b529","name":"OpenRouter Chat Model1","type":"@n8n/n8n-nodes-langchain.lmChatOpenRouter","position":[3920,400],"parameters":{"model":"google/gemini-2.0-flash-exp:free","options":{}},"credentials":{"openRouterApi":{"id":"pb06rfB4xmxzVe3Q","name":"OpenRouter"}},"typeVersion":1},{"id":"dcdcb7f2-669d-4e1b-a3f2-49a5b6c760b1","name":"Contain attachments?","type":"n8n-nodes-base.if","position":[260,500],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"5cf96104-c887-44fe-b528-30171943dd15","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{ $binary.isNotEmpty() }}","rightValue":""}]}},"typeVersion":2.2},{"id":"6280db8e-42e4-4f88-bbe7-4e65eff3a34f","name":"Get PDF and images attachments","type":"n8n-nodes-base.code","position":[600,300],"parameters":{"jsCode":"let results = [];\n\nfor (const item of $input.all()) {\n  for (key of Object.keys(item.binary)) {\n        results.push({\n            json: {},\n            binary: {\n                data: item.binary[key],\n            }\n        });\n    }\n}\n\nreturn results;"},"typeVersion":2},{"id":"53a7333d-fb49-46d4-9e3b-d186a5e416ca","name":"Extract from PDF","type":"n8n-nodes-base.extractFromFile","position":[1460,-540],"parameters":{"options":{},"operation":"pdf"},"typeVersion":1},{"id":"9d5c3b14-a3b0-4d2b-88d5-5a2c21a6907f","name":"PDF Analyzer","type":"@n8n/n8n-nodes-langchain.chainLlm","position":[1780,-540],"parameters":{"text":"=## PDF Summarization System Prompt\n\nYou are a specialized AI assistant tasked with creating concise, accurate summaries of documents. Your goal is to extract and distill the most important information from the content provided as input and present it in a clear, precise plain text summary.\n\n### Your responsibilities:\n\n1. Identify the main topic and purpose of the document\n2. Extract key points, arguments, findings, or conclusions\n3. Preserve essential data points, statistics, dates, and figures\n4. Recognize and highlight critical information and takeaways\n5. Maintain the original document's logical structure in your summary\n6. Prioritize information based on its significance to the document's purpose\n\n### Summary format:\n\n- Provide your summary in plain text only (no formatting)\n- Begin with a concise overview of the document's main topic and purpose\n- Present important points in a logical, sequential narrative\n- Use clear, direct language that accurately represents the original content\n- Maintain appropriate context for all extracted information\n- Keep the summary concise while including all crucial information\n- Use proper transitions between topics to maintain readability\n\n### What to exclude:\n\n- Minor details that don't contribute to the main points\n- Repetitive information\n- Extensive examples unless they're critical to understanding\n- Citations, references, and bibliographic details unless specifically important\n- Decorative or non-essential images (describe important visualized data if relevant)\n- Your own interpretations or opinions not supported by the document\n\n{{ $json.text }}","promptType":"define","hasOutputParser":true},"typeVersion":1.5},{"id":"ba6f6d2f-9a13-4bb4-80fb-72f5c4124473","name":"Save summary PDF","type":"n8n-nodes-base.googleSheets","position":[2580,-800],"parameters":{"columns":{"value":{"ID":"={{ $('Email Trigger (IMAP)').item.json.metadata[\"x-message-id\"] }}","DATE":"={{ $now.format('dd/LL/yyyy') }}","TYPE":"pdf","EMAIL":"={{ $('Email Trigger (IMAP)').item.json.from }}","SUBJECT":"={{ $('Email Trigger (IMAP)').item.json.subject }}","SUMMARY":"={{ $json.output.content }}"},"schema":[{"id":"DATE","type":"string","display":true,"required":false,"displayName":"DATE","defaultMatch":false,"canBeUsedToMatch":true},{"id":"EMAIL","type":"string","display":true,"required":false,"displayName":"EMAIL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"ID","type":"string","display":true,"required":false,"displayName":"ID","defaultMatch":false,"canBeUsedToMatch":true},{"id":"SUBJECT","type":"string","display":true,"required":false,"displayName":"SUBJECT","defaultMatch":false,"canBeUsedToMatch":true},{"id":"TYPE","type":"string","display":true,"required":false,"displayName":"TYPE","defaultMatch":false,"canBeUsedToMatch":true},{"id":"SUMMARY","type":"string","display":true,"required":false,"displayName":"SUMMARY","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1rBa0RI6XFfMerylVCV0dlKhJT_f4UAd8S6jyYX4aRRo/edit#gid=0","cachedResultName":"Foglio1"},"documentId":{"__rl":true,"mode":"list","value":"1rBa0RI6XFfMerylVCV0dlKhJT_f4UAd8S6jyYX4aRRo","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1rBa0RI6XFfMerylVCV0dlKhJT_f4UAd8S6jyYX4aRRo/edit?usp=drivesdk","cachedResultName":"Analyze Email + Attachments"}},"credentials":{"googleSheetsOAuth2Api":{"id":"JYR6a64Qecd6t8Hb","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"4c7ff16e-8649-4364-9aa6-c06670f4c36a","name":"All summaries","type":"n8n-nodes-base.merge","position":[3080,220],"parameters":{"numberInputs":3},"typeVersion":3},{"id":"46af5694-6b28-45e7-8b1b-d77482b326e7","name":"Map image summaries","type":"n8n-nodes-base.set","position":[2020,280],"parameters":{"options":{},"assignments":{"assignments":[{"id":"11592bed-7555-4e61-a692-d71b1a733fd4","name":"content","type":"string","value":"={{ $json.content }}"}]}},"typeVersion":3.4},{"id":"dc5858b7-c30b-413b-a1d0-143a068f2c87","name":"Upload attachments","type":"n8n-nodes-base.googleDrive","position":[1440,480],"parameters":{"name":"={{$now.format('yyyyLLddhhiiss')}}-{{ $binary.data.fileName }}","driveId":{"__rl":true,"mode":"list","value":"My Drive"},"options":{},"folderId":{"__rl":true,"mode":"list","value":"1CV5PgqBQIVFEacmbApdCApjNEtoNPzXQ","cachedResultUrl":"https://drive.google.com/drive/folders/1CV5PgqBQIVFEacmbApdCApjNEtoNPzXQ","cachedResultName":"Analyze attachments"}},"credentials":{"googleDriveOAuth2Api":{"id":"HEy5EuZkgPZVEa9w","name":"Google Drive account (n3w.it)"}},"typeVersion":3},{"id":"9537f678-163c-40de-93f3-9934f4ae2ad0","name":"Email summary","type":"n8n-nodes-base.set","position":[2000,800],"parameters":{"options":{},"assignments":{"assignments":[{"id":"ef348518-a9fb-4ea9-bd70-9dcf3bff092a","name":"content","type":"string","value":"={{ $json.response.text }}"}]}},"typeVersion":3.4},{"id":"ba0c45d9-7d5a-413e-9034-3e22a79ead77","name":"Send final summary","type":"n8n-nodes-base.telegram","position":[4340,220],"webhookId":"9c8e4675-762e-47dd-8cef-b94a5261ffd4","parameters":{"text":"={{ $json.text }}","chatId":"CHAT_ID","additionalFields":{}},"credentials":{"telegramApi":{"id":"0hSq9VwaiJifiscT","name":"Telegram account"}},"typeVersion":1.2},{"id":"7a97052b-37c5-4754-ac1a-0f1a20569df7","name":"Create final summary","type":"@n8n/n8n-nodes-langchain.chainLlm","position":[3940,220],"parameters":{"text":"=The inputs to synthesize are:\n'''\n{{ $json.output }}\n'''","messages":{"messageValues":[{"message":"## Comprehensive Email Analysis System Prompt\n\nYou are a specialized AI assistant tasked with creating a unified, concise summary of an email and all its attachments. Your input includes a summary of the email text, summaries of any images, and summaries of any PDF attachments. Your goal is to synthesize all this information into a single coherent summary that captures the essential message and purpose.\n\n### Your responsibilities:\n\n1. Identify the overarching theme or purpose connecting the email and its attachments\n2. Recognize relationships between the email content and the attached materials\n3. Extract and consolidate the most critical information from all sources\n4. Maintain proper context when combining information from different sources\n5. Prioritize information based on relevance to the email's main purpose\n6. Create a unified narrative that flows logically between email content and attachments\n\n### Input structure:\n- Email summary: A summary of the main email text\n- Image descriptions: Summaries of any images attached to the email\n- PDF summaries: Condensed versions of any PDF documents attached\n\n### Output format:\n\n- Provide your summary in plain text only\n- Begin with a one-sentence statement of the email's overall purpose and theme\n- Present a unified narrative that integrates information from the email and all attachments\n- Organize information by importance and relevance, not by source\n- Keep the final summary concise (5-7 sentences maximum) while including all essential information\n- Use clear transitions to maintain coherence when moving between different information sources\n- Preserve the original intent and tone of the communication\n\n### What to include:\n\n- The main topic and purpose of the communication\n- Key points from both the email and attachments\n- Critical requests, deadlines, or action items\n- Essential details like dates, figures, or specific references\n- Contextual information that clarifies the purpose of attachments\n\n### What to exclude:\n\n- Redundant information repeated across multiple sources\n- Minor details that don't contribute to understanding the main message\n- Excessive descriptions of attachments beyond their relevance to the email's purpose\n- Your own interpretations beyond what's supported by the input materials"}]},"promptType":"define"},"typeVersion":1.5},{"id":"99b4c22c-a29b-4b72-bc4a-bed5c1320386","name":"Save summary image","type":"n8n-nodes-base.googleSheets","position":[2020,20],"parameters":{"columns":{"value":{"ID":"={{ $('Email Trigger (IMAP)').item.json.metadata[\"x-message-id\"] }}","DATE":"={{ $now.format('dd/LL/yyyy') }}","TYPE":"image","EMAIL":"={{ $('Email Trigger (IMAP)').item.json.from }}","SUBJECT":"={{ $('Email Trigger (IMAP)').item.json.subject }}","SUMMARY":"={{ $json.content }}"},"schema":[{"id":"DATE","type":"string","display":true,"required":false,"displayName":"DATE","defaultMatch":false,"canBeUsedToMatch":true},{"id":"EMAIL","type":"string","display":true,"required":false,"displayName":"EMAIL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"ID","type":"string","display":true,"required":false,"displayName":"ID","defaultMatch":false,"canBeUsedToMatch":true},{"id":"SUBJECT","type":"string","display":true,"required":false,"displayName":"SUBJECT","defaultMatch":false,"canBeUsedToMatch":true},{"id":"TYPE","type":"string","display":true,"required":false,"displayName":"TYPE","defaultMatch":false,"canBeUsedToMatch":true},{"id":"SUMMARY","type":"string","display":true,"required":false,"displayName":"SUMMARY","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1rBa0RI6XFfMerylVCV0dlKhJT_f4UAd8S6jyYX4aRRo/edit#gid=0","cachedResultName":"Foglio1"},"documentId":{"__rl":true,"mode":"list","value":"1rBa0RI6XFfMerylVCV0dlKhJT_f4UAd8S6jyYX4aRRo","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1rBa0RI6XFfMerylVCV0dlKhJT_f4UAd8S6jyYX4aRRo/edit?usp=drivesdk","cachedResultName":"Analyze Email + Attachments"}},"credentials":{"googleSheetsOAuth2Api":{"id":"JYR6a64Qecd6t8Hb","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"2b32c086-c436-436e-93c3-da88e6f08247","name":"Save summary text","type":"n8n-nodes-base.googleSheets","position":[2020,1040],"parameters":{"columns":{"value":{"ID":"={{ $('Email Trigger (IMAP)').item.json.metadata[\"x-message-id\"] }}","DATE":"={{ $now.format('dd/LL/yyyy') }}","TYPE":"email","EMAIL":"={{ $('Email Trigger (IMAP)').item.json.from }}","SUBJECT":"={{ $('Email Trigger (IMAP)').item.json.subject }}","SUMMARY":"={{ $json.response.text }}"},"schema":[{"id":"DATE","type":"string","display":true,"required":false,"displayName":"DATE","defaultMatch":false,"canBeUsedToMatch":true},{"id":"EMAIL","type":"string","display":true,"required":false,"displayName":"EMAIL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"ID","type":"string","display":true,"required":false,"displayName":"ID","defaultMatch":false,"canBeUsedToMatch":true},{"id":"SUBJECT","type":"string","display":true,"required":false,"displayName":"SUBJECT","defaultMatch":false,"canBeUsedToMatch":true},{"id":"TYPE","type":"string","display":true,"required":false,"displayName":"TYPE","defaultMatch":false,"canBeUsedToMatch":true},{"id":"SUMMARY","type":"string","display":true,"required":false,"displayName":"SUMMARY","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1rBa0RI6XFfMerylVCV0dlKhJT_f4UAd8S6jyYX4aRRo/edit#gid=0","cachedResultName":"Foglio1"},"documentId":{"__rl":true,"mode":"list","value":"1rBa0RI6XFfMerylVCV0dlKhJT_f4UAd8S6jyYX4aRRo","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1rBa0RI6XFfMerylVCV0dlKhJT_f4UAd8S6jyYX4aRRo/edit?usp=drivesdk","cachedResultName":"Analyze Email + Attachments"}},"credentials":{"googleSheetsOAuth2Api":{"id":"JYR6a64Qecd6t8Hb","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"135bf3c3-e45f-4363-857b-2345e0bc7964","name":"Convert text","type":"n8n-nodes-base.markdown","position":[860,940],"parameters":{"html":"={{ $json.textHtml }}","options":{}},"typeVersion":1},{"id":"0c2cf33a-d7bb-438d-a9c9-06a77f91b56e","name":"Gemini 2.0 Flash","type":"@n8n/n8n-nodes-langchain.lmChatOpenRouter","position":[1700,-320],"parameters":{"model":"google/gemini-2.0-flash-exp:free","options":{}},"credentials":{"openRouterApi":{"id":"pb06rfB4xmxzVe3Q","name":"OpenRouter"}},"typeVersion":1},{"id":"50d5fd05-db5f-451c-92ce-e0f42d8322f9","name":"Parsing","type":"n8n-nodes-base.code","position":[3360,220],"parameters":{"jsCode":"const inputData = $input.all();\n\nconst outputData = inputData.map(item => {\n  \n  const outputValue = item.json.output || item.json.content;\n\n  return {\n    data: {\n      output: outputValue \n    }\n  };\n});\n\nreturn outputData;"},"typeVersion":2},{"id":"801659a1-cc9d-4014-9403-d6d0952e856a","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[520,220],"parameters":{"width":260,"height":240,"content":"Get all attachments present in the email (in this WF only PDFs and images are considered)"},"typeVersion":1},{"id":"15dc13b9-b35c-43d3-8af9-a8793382a2b6","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[1740,-600],"parameters":{"width":340,"height":200,"content":"Analyze the content of PDF files and make a summary for each one"},"typeVersion":1},{"id":"6c68ce17-13f1-4aba-9f43-e4003e5cd723","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1380,120],"parameters":{"height":200,"content":"Analyze the content of the image and describe it accurately"},"typeVersion":1},{"id":"ff746258-dc11-43aa-afe9-06c9dfb3708b","name":"Analyze image","type":"@n8n/n8n-nodes-langchain.openAi","position":[1440,180],"parameters":{"text":"## Image Analysis System Prompt\n\nYou are a specialized AI assistant focused on analyzing images. Your task is to carefully examine the image provided as input and produce a detailed, accurate description in plain text format.\n\n### Your responsibilities:\n\n1. Observe and describe the main subject(s) or focal point(s) of the image\n2. Identify notable objects, people, animals, or other elements present\n3. Describe the setting, background, and environment if applicable\n4. Note any text visible in the image, transcribing it accurately\n5. Recognize any actions, activities, or events taking place\n6. Identify relevant contextual information (time of day, weather, season, etc.)\n7. Describe colors, lighting, composition, and other visual elements when relevant\n\n### Response format:\n\n- Provide your analysis in plain text only (no HTML, markdown, or other formatting)\n- Begin with a concise overview of what the image depicts\n- Follow with a detailed description covering all significant elements\n- Organize information logically, typically moving from main subjects to background details\n- Use clear, descriptive language that accurately represents what is actually visible\n- Keep descriptions objective and factual\n\n### What to exclude:\n\n- Speculation about elements not clearly visible in the image\n- Subjective judgments or interpretations beyond what is objectively present\n- Personal opinions about the quality or purpose of the image\n- Complex technical analysis unless specifically relevant\n- Any formatting beyond plain text\n\nThe image to analyze is the one provided in the input.","modelId":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"GPT-4O-MINI"},"options":{},"resource":"image","inputType":"base64","operation":"analyze"},"credentials":{"openAiApi":{"id":"CDX6QM4gLYanh0P4","name":"OpenAi account"}},"typeVersion":1.8},{"id":"ce353f02-72ff-49bf-9297-5a2b3229fa49","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[1340,740],"parameters":{"width":320,"height":180,"content":"Analyze the content of the email and summarize it"},"typeVersion":1},{"id":"01ee4c00-5993-47ce-af04-320cd3319593","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[3060,100],"parameters":{"width":720,"height":80,"content":"All the summaries of the email components (text, PDF, images) are aggregated and a final summary is generated"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"30310971-f23c-4761-823c-36ddad8bc8dd","connections":{"Switch":{"main":[[{"node":"Upload attachments","type":"main","index":0},{"node":"Extract from PDF","type":"main","index":0}],[{"node":"Upload attachments","type":"main","index":0},{"node":"Analyze image","type":"main","index":0}]]},"Parsing":{"main":[[{"node":"Aggregate","type":"main","index":0}]]},"Aggregate":{"main":[[{"node":"Create final summary","type":"main","index":0}]]},"Split Out":{"main":[[{"node":"All summaries","type":"main","index":0}]]},"DeepSeek R1":{"ai_languageModel":[[{"node":"Email Summarization Chain","type":"ai_languageModel","index":0}]]},"Convert text":{"main":[[{"node":"Email Summarization Chain","type":"main","index":0}]]},"PDF Analyzer":{"main":[[{"node":"Save summary PDF","type":"main","index":0},{"node":"Split Out","type":"main","index":0}]]},"All summaries":{"main":[[{"node":"Parsing","type":"main","index":0}]]},"Analyze image":{"main":[[{"node":"Save summary image","type":"main","index":0},{"node":"Map image summaries","type":"main","index":0}]]},"Email summary":{"main":[[{"node":"All summaries","type":"main","index":2}]]},"Extract from PDF":{"main":[[{"node":"PDF Analyzer","type":"main","index":0}]]},"Gemini 2.0 Flash":{"ai_languageModel":[[{"node":"PDF Analyzer","type":"ai_languageModel","index":0}]]},"Save summary PDF":{"main":[[]]},"Save summary text":{"main":[[]]},"Save summary image":{"main":[[]]},"Upload attachments":{"main":[[]]},"Map image summaries":{"main":[[{"node":"All summaries","type":"main","index":1}]]},"Contain attachments?":{"main":[[{"node":"Get PDF and images attachments","type":"main","index":0},{"node":"Convert text","type":"main","index":0}],[{"node":"Convert text","type":"main","index":0}]]},"Create final summary":{"main":[[{"node":"Send final summary","type":"main","index":0}]]},"Email Trigger (IMAP)":{"main":[[{"node":"Contain attachments?","type":"main","index":0}]]},"OpenRouter Chat Model1":{"ai_languageModel":[[{"node":"Create final summary","type":"ai_languageModel","index":0}]]},"Structured Output Parser":{"ai_outputParser":[[{"node":"PDF Analyzer","type":"ai_outputParser","index":0}]]},"Email Summarization Chain":{"main":[[{"node":"Save summary text","type":"main","index":0},{"node":"Email summary","type":"main","index":0}]]},"Get PDF and images attachments":{"main":[[{"node":"Switch","type":"main","index":0}]]}}}


name: Turn YouTube Videos into Summaries, Transcripts, and Visual Insights
author_name: Colleen Brady
author_username: colleen
nodes_used: ["n8n-nodes-base.httpRequest","n8n-nodes-base.code"]
categories: []
created_at: 2025-03-17T02:41:29.515Z
updated_at: 2025-03-17T02:41:29.515Z
url: https://n8n.io/workflows/3188
scraped_at: 2025-06-19 22:50:02
description:
  Who is this for?  

  This workflow is built for anyone who works with YouTube content, whether you're:  

  A learner looking to understand a video’s key points  
  A content creator repurposing video material  
  A YouTube manager looking to update titles, descriptions
  A social media strategist searching for the most shareable clips  


  Don't just ask questions about what's said. Find out what's going on in a video too.

  Video Overview: https://www.youtube.com/watch?v=Ovg_KfKxnC8

  What problem does this solve?  

  YouTube videos hold valuable insights, but watching and processing them manually takes time. This workflow automates:  

  Quick content extraction**: Summarize key ideas without watching full videos   
  Visual analysis**: Understand what’s happening beyond spoken words  
  Clip discovery**: Identify the best moments for social sharing  

  How the workflow works  

  This n8n-powered automation:  

  Uses Google’s Gemini 1.5 Flash AI for intelligent video analysis  
  Provides multiple content analysis templates tailored to different needs  

  What makes this workflow powerful?  

  The easiest place to start is by requesting a summary or transcript. From there, you can refine the prompts to match your specific use case and the type of video content you’re working with.  

  But what's even more amazing? You can ask questions about what’s happening in the video — and get detailed insights about the people, objects, and scenes. It's jaw-dropping.  

  This workflow is versatile — the actions adapt based on the values set. That means you can use a single workflow to:  

  Extract transcripts  
  Generate an extended YouTube description  
  Write a summary blog post  

  You can also modify the trigger based on how you want to run the workflow — use a webhook, connect it to an event in Airtable, or leave it as-is for on-demand use. The output can then be sent anywhere: Notion, Airtable, CMS platforms, or even just stored for reference.  

  How to set it up  

  Connect your Google API key  
  Paste a YouTube video URL  
  Select an analysis method  
  Run the workflow and get structured results  

  Analysis Templates  

  Basic & Timestamped Transcripts**: Extract spoken content  
  Summaries**: Get concise takeaways  
  Visual Scene Analysis**: Detect objects, settings, and people  
  Clip Finder**: Locate shareable moments  
  Actionable Insights**: Extract practical information  

  Customization Options  

  Modify templates to fit your needs  
  Connect with external platforms  
  Adjust formatting preferences  

  Advanced Configuration  

  This workflow is designed for use with gemini-1.5-flash. In the future, you can update the flow to work with different models or even modify the HTTP request node to define which API endpoint should be used. 

  It's also been designed so you can use this flow on it's own or add to a new / existing worflow. 

  This workflow helps you get the most out of YouTube content — quickly and efficiently.

workflow_json:
  {"id":"wZBgoWrBZveMmzYi","meta":{"instanceId":"147b9b53621dbd6fca5f762b57fc3fabf293d676d0c08463ec52c91332ab391f","templateCredsSetupCompleted":true},"name":"Turn YouTube Videos into Summaries, Transcripts, and Visual Insights","tags":[],"nodes":[{"id":"61c56de7-0d8e-44fe-baf3-3e33ddd35b21","name":"When clicking ‘Test workflow’","type":"n8n-nodes-base.manualTrigger","position":[-1340,120],"parameters":{},"typeVersion":1},{"id":"4e43030c-16cd-4b77-8c58-c3b703646a16","name":"Set: Define Initial Variables","type":"n8n-nodes-base.set","position":[-840,120],"parameters":{"options":{},"assignments":{"assignments":[{"id":"72590fa0-cf12-4249-80fc-7aaec9992390","name":"automationID","type":"string","value":"optional-enter-reference-tracking-identifier"},{"id":"24e9b1c3-2955-4e0b-9b4b-a6b9d046fb72","name":"apiKey","type":"string","value":"enter-your-api-key-here"},{"id":"b6600a42-1b8d-486a-a51d-0868bc45452e","name":"youtubeURL","type":"string","value":"https://www.youtube.com/watch?v=Ovg_KfKxnC8"},{"id":"ce9a9a40-5ae4-4106-ae61-0daba2ec185f","name":"promptType","type":"string","value":"transcript"}]}},"typeVersion":3.4},{"id":"add611c6-c053-464c-b12b-f0f20b4c3c4f","name":"Switch: What kind of question do we want to ask?","type":"n8n-nodes-base.switch","onError":"continueRegularOutput","position":[-200,60],"parameters":{"rules":{"values":[{"outputKey":"Transcript","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"4ba139e4-2fd7-473f-869d-f27a1a2f3823","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.promptType.toLowerCase() }}","rightValue":"transcript"}]},"renameOutput":true},{"outputKey":"Transcript with Timestamps","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"486f3c1c-7203-4bc5-a796-87939d4360c5","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.promptType.toLowerCase() }}","rightValue":"timestamps"}]},"renameOutput":true},{"outputKey":"Summary","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"814597ad-12ff-450d-a4bc-cd2eb2836d8f","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.promptType.toLowerCase() }}","rightValue":"summary"}]},"renameOutput":true},{"outputKey":"Scene Description","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"759debf2-3dfb-4bdd-b41f-7ef0a709e25e","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.promptType.toLowerCase() }}","rightValue":"scene"}]},"renameOutput":true},{"outputKey":"Clips","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"5c66a390-2566-461d-b9bc-b0e7ebdc4af8","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.promptType.toLowerCase() }}","rightValue":"clips"}]},"renameOutput":true}]},"options":{"fallbackOutput":"extra"}},"typeVersion":3.2,"alwaysOutputData":false},{"id":"96b6a6c7-3b4f-412d-b200-526971782346","name":"Set: Scene Prompt","type":"n8n-nodes-base.set","position":[480,220],"parameters":{"options":{},"assignments":{"assignments":[{"id":"8be68e95-53df-492f-a88a-14c06f51f531","name":"prompt","type":"string","value":"=Please provide a detailed description of the scene in the video, including:\n\nSetting: Where the scene takes place (e.g., indoors, outdoors, specific location). Be specific - is it a forest, a city street, a living room?\n\nObjects: Prominent objects visible in the scene (e.g., furniture, vehicles, natural elements). Include details like color, size, and material if discernible.\n\nPeople: Description of any people present, including their appearance (clothing, hair, etc.), approximate age, and any actions they are performing.\n\nLighting: The overall lighting of the scene (e.g., bright, dim, natural, artificial). Note any specific light sources (lamps, sunlight).\n\nColors: Dominant colors and color palettes used in the scene.\n\nCamera Angle/Movement: Describe the camera perspective (e.g., close-up, wide shot, aerial view) and any camera movement (panning, zooming, static).\n\nStart output directly with the response -- do not include any introductory text or explanations."},{"id":"bfa3b421-643d-4a52-93e9-0830f794140b","name":"model","type":"string","value":"gemini-1.5-flash"}]},"includeOtherFields":true},"typeVersion":3.4},{"id":"7506b5fa-be12-4d34-8583-027bc782db0d","name":"Set: Summarize Prompt","type":"n8n-nodes-base.set","position":[480,20],"parameters":{"options":{},"assignments":{"assignments":[{"id":"8be68e95-53df-492f-a88a-14c06f51f531","name":"prompt","type":"string","value":"=Provide a concise summary of the main points in nested bullets, using quotes only when absolutely essential for clarity. Start output directly with the response."},{"id":"ccc44699-0918-4837-89a6-c763b157fc8c","name":"model","type":"string","value":"gemini-1.5-flash"}]},"includeOtherFields":true},"typeVersion":3.4},{"id":"2aaf482d-af31-4cd8-9014-7b77efbf3021","name":"Set: Transcript Prompt","type":"n8n-nodes-base.set","position":[480,-380],"parameters":{"options":{},"assignments":{"assignments":[{"id":"8be68e95-53df-492f-a88a-14c06f51f531","name":"prompt","type":"string","value":"=Transcribe the video. Return only the spoken dialogue, verbatim. Omit any additional text or descriptions."},{"id":"b445c2da-934f-4a78-a57b-f383d8950f8a","name":"model","type":"string","value":"gemini-1.5-flash"}]},"includeOtherFields":true},"typeVersion":3.4},{"id":"75a6ac10-00c2-45ab-88b7-dfec3cd58bf2","name":"Set: Fallback","type":"n8n-nodes-base.set","position":[480,620],"parameters":{"options":{},"assignments":{"assignments":[{"id":"8be68e95-53df-492f-a88a-14c06f51f531","name":"prompt","type":"string","value":"=Summarize this YouTube video with a focus on actionable insights. Use nested bullets and include relevant quotes. Specifically, highlight any recommended tools, strategies, or resources mentioned."},{"id":"da626eb8-a097-4a65-834d-4d1709aed260","name":"model","type":"string","value":"gemini-1.5-flash"}]},"includeOtherFields":true},"typeVersion":3.4},{"id":"29ef7f9f-34c9-46f5-96f9-17b42feea381","name":"Set: Transcript with Timestamps Prompt","type":"n8n-nodes-base.set","position":[480,-180],"parameters":{"options":{},"assignments":{"assignments":[{"id":"8be68e95-53df-492f-a88a-14c06f51f531","name":"prompt","type":"string","value":"=Generate a timestamped transcript of the video. Each line must follow this format precisely:  [hh:mm:ss] Dialogue. Return only the timestamp and spoken content; omit any other text or formatting.  "},{"id":"98ca7af8-0fbd-4ba8-8fc8-f914e5bbe48a","name":"model","type":"string","value":"gemini-1.5-flash"}]},"includeOtherFields":true},"typeVersion":3.4},{"id":"e10524ed-09dd-4c0f-86b0-9161fa347821","name":"Set: Scene Clips","type":"n8n-nodes-base.set","position":[480,420],"parameters":{"options":{},"assignments":{"assignments":[{"id":"8be68e95-53df-492f-a88a-14c06f51f531","name":"prompt","type":"string","value":"=Extract shareable clips for social media. Each clip must include:\n\n* **Timestamp:** [hh:mm:ss]-[hh:mm:ss]\n* **Transcript:** Verbatim dialogue/text within the clip.\n* **Rationale:**  A concise explanation (under 20 words) of the clip's social media appeal (e.g., \"humorous,\" \"controversial,\" \"inspiring,\" \"informative\").  Focus on virality, engagement potential (shares, likes, comments).\n\nStart output directly with the response -- do not include any introductory text or explanations."},{"id":"0493ffa7-4fef-4e48-b9d7-7f0891660325","name":"model","type":"string","value":"gemini-1.5-flash"}]},"includeOtherFields":true},"typeVersion":3.4},{"id":"be66d323-9035-4123-8086-dde14e528dc8","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-2340,-600],"parameters":{"width":780,"height":820,"content":"# How to Use This Workflow\n\nVideo Overview: [https://www.youtube.com/watch?v=Ovg_KfKxnC8](https://www.youtube.com/watch?v=Ovg_KfKxnC8)\n\nUse this workflow to analyze YouTube videos effortlessly. Start by requesting a summary or transcript—then refine the prompts to fit your needs and the type of content you're working with.\n\nEven more impressive? You can ask specific questions about what’s happening in a video—identifying people, scenes, and visual details. The ability to extract this level of insight is game-changing.\n\nThis workflow is highly adaptable—actions adjust based on the values you set. With a single flow, you can generate transcripts, create detailed YouTube descriptions, and draft summary blog posts.\n\nTriggers are flexible, too. Run it manually, connect it to a webhook, or automate it through Airtable or another system. The output can go anywhere -- Notion, Google Docs, CMS platforms -- or simply stay in n8n for on-the-fly analysis.\n\nThis workflow was created using n8n 1.82.3.\n\n## Requirements\n* [Google API key](https://console.developers.google.com/) (or obtain via [AI Studio](https://aistudio.google.com/apikey))\n\n## Testing\n* This workflow was tested on an assortment of public YouTube videos from shorts up to about an hour in length.\n\n## Future-proofing\n* This workflow was created for use with gemini-1.5-flash. In the future, the set nodes for prompts could be updated to use different models and possibly add in what API endpoint should be used in the http node.\n\n## Documentation\n* [Explore vision capabilities with the Gemini API](https://ai.google.dev/gemini-api/docs/vision?lang=python)\n* [Pricing](https://ai.google.dev/gemini-api/docs/pricing)"},"typeVersion":1},{"id":"a8f5541c-d267-4998-bb31-32f2684b0874","name":"Set Fields: Define Outcome","type":"n8n-nodes-base.set","position":[2800,120],"parameters":{"include":"except","options":{},"assignments":{"assignments":[{"id":"300bfbe7-8d13-41ba-8828-17bba1d0eabe","name":"answerAIGenerated","type":"string","value":"={{ $json.candidates?.[0]?.content?.parts?.[0]?.text ? $json.candidates[0].content.parts[0].text : ($json.error ? $json.error : \"No content or error found\") }}"},{"id":"a54eeb5d-e4de-4fd9-a15c-be51cc414c46","name":"promptTokenCount","type":"string","value":"={{ $json.usageMetadata?.promptTokenCount ? $json.usageMetadata.promptTokenCount : ($json.error ? $json.error : \"No content or error found\") }}"},{"id":"dd590788-069e-48d9-adb2-6a5d10f8af2f","name":"candidatesTokenCount","type":"string","value":"={{ $json.usageMetadata?.candidatesTokenCount ? $json.usageMetadata.candidatesTokenCount : ($json.error ? $json.error : \"No content or error found\") }}"},{"id":"23766495-25df-4d3d-bc62-9e79a860ee19","name":"totalTokenCount","type":"string","value":"={{ $json.usageMetadata?.totalTokenCount ? $json.usageMetadata.totalTokenCount : ($json.error ? $json.error : \"No content or error found\") }}"},{"id":"cfad5ba2-a2c5-48ff-b64b-9131a51fd23c","name":"modelVersionUsed","type":"string","value":"={{ $json.modelVersion ? $json.modelVersion : ($json.error ? $json.error : \"No content or error found\") }}"}]},"excludeFields":"candidates, usageMetadata","includeOtherFields":true},"typeVersion":3.4},{"id":"062b5d41-27bb-4e67-8ffa-6e3e392fb437","name":"HTTP Request to Google","type":"n8n-nodes-base.httpRequest","onError":"continueRegularOutput","position":[1740,120],"parameters":{"url":"=https://generativelanguage.googleapis.com/v1beta/models/{{ $json.model }}:generateContent?key={{ $json.apiKey }}","method":"POST","options":{},"jsonBody":"={\n  \"contents\": [{\n    \"parts\": [\n      { \"text\": {{ JSON.stringify($json.prompt) }} },\n      { \"file_data\": { \"file_uri\": \"{{ $json.youtubeURL }}\" } }\n    ]\n  }]\n}","sendBody":true,"sendHeaders":true,"specifyBody":"json","headerParameters":{"parameters":[{"name":"Content-Type","value":"application/json"}]}},"typeVersion":4.2,"alwaysOutputData":true},{"id":"0a204e60-674a-453d-81e1-9eb59a3214e2","name":"Set: Merged Values","type":"n8n-nodes-base.set","position":[1380,120],"parameters":{"options":{},"includeOtherFields":true},"typeVersion":3.4},{"id":"48ed5162-61e1-4077-a13a-b2cf135fc11e","name":"If: Was an error detected?","type":"n8n-nodes-base.if","disabled":true,"position":[2560,780],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"148e9a72-f826-468c-86a3-471873717ed4","operator":{"type":"string","operation":"exists","singleValue":true},"leftValue":"={{ $json.error }}","rightValue":""}]}},"typeVersion":2.2},{"id":"f9c0ef37-da99-4100-bd04-b5f2ac93a694","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-2340,280],"parameters":{"width":780,"height":3580,"content":"## Prompt Inspiration Ideas\n\nUse these prompts as inspiration for your workflow. A quick way to iterate on ideas is to try them in [https://aistudio.google.com/](https://aistudio.google.com/).\n\n### 📝 Essential Video Summarizer (Quick Content Digestion)\nProvide a concise summary of the main points of this YouTube video in nested bullets, using quotes only when absolutely essential for clarity.\n\nStart output directly with the response -- do not include any introductory text or explanations.\n\n### 🚀 Complete YouTube SEO Package Generator (Content Marketing)\n\nGenerate a complete YouTube package (Title, Description, Keywords, and Timestamps) based on the following transcript:\n\n**Instructions:**\n\n* **Title:** Craft a concise and engaging title (under 60 characters) that accurately reflects the video's content and will attract viewers.  \n* **Description:** Write a detailed description (around 150-200 words) summarizing the key topics covered in the video.  This description should:\n    * Clearly outline the value proposition for the viewer (what they will learn or gain).\n    * Include relevant keywords to improve searchability.\n    * Feature a strong call to action (e.g., subscribe, visit a website, follow on social media).\n    * Optionally include a brief, intriguing hook at the beginning to grab the viewer's attention.\n* **Keywords:** Generate a list of relevant keywords and tags (around 10-15) that accurately describe the video's content and will help viewers find it in search results.  Consider:\n    * Specific topics discussed\n    * Related terms and concepts\n    * Industry jargon (if applicable)\n    * Names of people or products mentioned\n* **Timestamps:**  Generate timestamps for key topics or sections within the video. These should be formatted clearly for easy navigation.  For example:\n    * 0:00 Introduction\n    * 1:15 Topic 1\n    * 3:45 Topic 2 ...etc.  \n\n**Important Considerations:**\n\n* **Target Audience:** Assume the target audience is [Describe your target audience – e.g., beginners learning Python, experienced marketers, people interested in gardening].\n* **Overall Tone:** The tone of the entire package should be [Specify the desired tone – e.g., informative and educational, enthusiastic and engaging, humorous and lighthearted].\n* **Video's Purpose:** The primary goal of the video is to [State the video's objective – e.g., teach a skill, provide information, entertain, persuade].\n\n\n**Optional:**\n* If the video promotes a product, service, or other content, include relevant links in the description.\n* If there are any specific phrases or branding elements that should be included, specify them here.\n\nStart output directly with the response -- do not include any introductory text or explanations.\n\n### 🗺️ Structured Video Content Map (Educational Organization)\n\nSummarize the key points of this YouTube video with no introductory text. Follow this structured format:\n\nMain Topics\n* Organize content using Level 2 headers (##) based on key themes.\n\nUnder each header:\n* List only the most essential concepts using concise bullet points.\n* Ensure technical accuracy while maintaining clarity.\n\nOrganize sections in this order when applicable:\n* Overview & Context\n* Core Concepts & Features\n* How It Works\n* Benefits & Drawbacks\n\nFormatting Rules:\n* Use Markdown for structured readability.\n* Keep bullet points simple (avoid nesting).\n* No summaries, conclusions, or extra explanations -- just structured content.\n\n### 🎯 Goal-Oriented Learning Digest (Personal Development)\n\nI'm trying to learn about [Specific Goal, e.g., \"how to improve my public speaking skills,\" \"the latest trends in web development\"]. Summarize the relevant information using nested bullets and quotes, focusing on how it helps me achieve this goal.\n\nStart output directly with the response -- do not include any introductory text or explanations.\n\n### ⚙️ Actionable Insights Framework (Implementation Planning)\n\nExtract actionable insights with a focus on practical applications and recommendations.\n\nStart output directly with the response—do not include any introductory text or explanations.\n\nFormat the summary using markdown and follow this structure:\n\nProblem Statement\n* Summarize the core issue or topic addressed.\n\nKey Solutions & Recommendations\n* Use separate ## headers for each major solution or recommendation.\n\nImplementation Steps:\n* Under each solution, list key steps using bullet points.\n\nExpected Outcomes & Benefits:\n* Describe the potential impact and advantages of each solution.\n\nResources & Tools\n* List any relevant tools, frameworks, or resources mentioned.\n\n### 💡 Concept Extractor with Supporting Quotes (Deep Content Analysis)\n\nExtract the core concepts presented using nested bullets. Include supporting quotes for each concept. Focus on [Specific Topic/Area, e.g., \"the impact of AI on marketing,\" \"the principles of effective communication,\" etc.].\n\nStart output directly with the response -- do not include any introductory text or explanations.\n\n\n### 👥 Audience-Targeted Video Analysis (Professional Development)\n\nAnalyze this video for a target audience of [Specify Target Audience, e.g., \"software engineers,\" \"marketing professionals,\" \"general readers\"].\n\nFormat the summary using markdown and structure it as follows:\n\nMain Topics\nOrganize key points under Level 2 headers (##), focusing on essential insights.\nSuggested sections (adjust as needed):\nOverview (context & background)\nKey Concepts & Features\nHow It Works (technical or practical explanation)\nBenefits & Challenges\nKey Instructions:\n\nTailor content to the [Target Audience] and their expected level of expertise.\nUse bullet points for clarity and conciseness.\nBold key terms to emphasize important ideas.\nEnsure technical accuracy, simplifying complex ideas only when needed.\nUse tables when making comparisons.\nLength Guidance:\n\nSummarize in approximately [Specify Desired Length, e.g., \"200 words,\" \"500 words,\" \"one page\"].\n\nStart output directly with the response -- do not include any introductory text or explanations.\n\n### 🧠 Knowledge Extension Analyzer (Advanced Learning & Analysis)\n\nAssuming I already understand [briefly state relevant background knowledge], provide specific insights that build upon this knowledge. Use nested bullets and relevant quotes.\n\nStart output directly with the response -- do not include any introductory text or explanations.\n\n### 🔍 Argument Analysis Blueprint (Critical Thinking)\n\nAnalyze the argument presented in this video. Outline the main claims and supporting evidence using nested bullets. Include direct quotes to illustrate key points. Identify any potential counterarguments or weaknesses in the reasoning.\n\nStart output directly with the response -- do not include any introductory text or explanations.\n\n### ⚖️ YouTube Argument Analyzer (Debate & Rhetoric)\n\nAnalyze the argument presented in this YouTube video. Outline the main claims and supporting evidence using nested bullets. Include direct quotes to illustrate key points. Identify any potential counterarguments or weaknesses in the reasoning.\n\nStart output directly with the response -- do not include any introductory text or explanations.\n\n### 🎭 Rhetorical Technique Evaluator (Communication Analysis)\n\nAnalyze the speaker's [e.g., presentation style, persuasive techniques, use of rhetoric]. Use nested bullets and include specific quotes to illustrate your observations. Focus on how these techniques contribute to (or detract from) the video's overall message.\n\nStart output directly with the response -- do not include any introductory text or explanations.\n\n"},"typeVersion":1},{"id":"d15f5fa4-731d-4d63-a065-e81a5248e8d8","name":"Code: Merge data from prior nodes with HTTP Output","type":"n8n-nodes-base.code","position":[2340,120],"parameters":{"mode":"runOnceForEachItem","jsCode":"return {\n  json: {\n    ...$json, // Keep data from http request\n    ...$('Set: Merged Values').item.json, // Keep data from before http request\n  }\n};\n\n\n\n"},"typeVersion":2},{"id":"eb3b45bc-c59e-45f7-a352-97f62ae079f2","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-1080,-80],"parameters":{"width":560,"height":520,"content":"## ✏️ Set Values For Use in Flow\n1. automationID: Use this to reference the automation. Useful for troubleshooting when you have lots of flows running.\n2. apiKey: API key from Google\n3. youtubeURL: Public URL for video to be processed\n4. promptType: Used by switch node and determines which prompt is sent as part of API call."},"typeVersion":1},{"id":"440539da-e658-404f-8f85-9e28e9acffc9","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[-460,-80],"parameters":{"width":560,"height":520,"content":"## ℹ️ Determine which prompt will be passed in API call based on promptType value\n"},"typeVersion":1},{"id":"ba3f3e35-d691-449e-9f62-d2246223ff5e","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[280,-580],"parameters":{"width":560,"height":1520,"content":"## ✏️ Set Values For Prompts & Model\n1. prompt: What do you want to know about a video\n2. model: Which model to use (gemini-1.5-flash)"},"typeVersion":1},{"id":"b33de065-16d5-4b29-8117-91cfd9d9034a","name":"Sticky Note9","type":"n8n-nodes-base.stickyNote","position":[1300,-60],"parameters":{"width":260,"height":520,"content":"## ℹ️ Making it easier to reference values in the http node\n"},"typeVersion":1},{"id":"eb6788d8-4b99-42e5-b0c1-0430a8d786e6","name":"Sticky Note10","type":"n8n-nodes-base.stickyNote","position":[2420,580],"parameters":{"width":560,"height":520,"content":"## ℹ️ If you want to add special processing when errors occur (Optional)\n\n"},"typeVersion":1},{"id":"432ef0bf-8c85-4f72-a771-42b3b2173094","name":"Sticky Note11","type":"n8n-nodes-base.stickyNote","position":[1680,-60],"parameters":{"width":260,"height":520,"content":"## ℹ️ Makes call to Google endpoint using values set in earlier nodes\n\n"},"typeVersion":1},{"id":"57f29827-7f1f-4b73-b700-51af8bd1e582","name":"Sticky Note13","type":"n8n-nodes-base.stickyNote","position":[2240,-60],"parameters":{"width":300,"height":520,"content":"## ℹ️ Merges data from returned by Google with values set in prior nodes so that earlier data isn't lost"},"typeVersion":1},{"id":"c42daf8b-2d9e-4258-91be-97b830c4eff4","name":"Sticky Note14","type":"n8n-nodes-base.stickyNote","position":[2700,-60],"parameters":{"width":300,"height":520,"content":"## ℹ️ Gives returned data meaningful names; Simplifies amount of data available to follow-on nodes"},"typeVersion":1},{"id":"fb246216-645d-4c01-adc7-9b2be2920bcd","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-1460,280],"parameters":{"width":360,"content":"#### 💡 Trigger Ideas\nYou can change the trigger to meet your use case. If you need to run it once in awhile, can leave in current format. Try one of n8n's YouTube nodes, a form, a webhook, etc. for running more frequently as part of an automation."},"typeVersion":1},{"id":"ba228de2-c2de-475c-95c3-20ef712edcc9","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[3120,100],"parameters":{"width":360,"height":240,"content":"#### 💡 Next Step Ideas\nUse a webhook to send data to another destination or use one of n8n's other nodes to send to Airtable, Notion, etc."},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"5d83e29e-caf0-4c3a-be04-9da966904a5a","connections":{"Set: Fallback":{"main":[[{"node":"Set: Merged Values","type":"main","index":0}]]},"Set: Scene Clips":{"main":[[{"node":"Set: Merged Values","type":"main","index":0}]]},"Set: Scene Prompt":{"main":[[{"node":"Set: Merged Values","type":"main","index":0}]]},"Set: Merged Values":{"main":[[{"node":"HTTP Request to Google","type":"main","index":0}]]},"Set: Summarize Prompt":{"main":[[{"node":"Set: Merged Values","type":"main","index":0}]]},"HTTP Request to Google":{"main":[[{"node":"Code: Merge data from prior nodes with HTTP Output","type":"main","index":0},{"node":"If: Was an error detected?","type":"main","index":0}]]},"Set: Transcript Prompt":{"main":[[{"node":"Set: Merged Values","type":"main","index":0}]]},"Set: Define Initial Variables":{"main":[[{"node":"Switch: What kind of question do we want to ask?","type":"main","index":0}]]},"When clicking ‘Test workflow’":{"main":[[{"node":"Set: Define Initial Variables","type":"main","index":0}]]},"Set: Transcript with Timestamps Prompt":{"main":[[{"node":"Set: Merged Values","type":"main","index":0}]]},"Switch: What kind of question do we want to ask?":{"main":[[{"node":"Set: Transcript Prompt","type":"main","index":0}],[{"node":"Set: Transcript with Timestamps Prompt","type":"main","index":0}],[{"node":"Set: Summarize Prompt","type":"main","index":0}],[{"node":"Set: Scene Prompt","type":"main","index":0}],[{"node":"Set: Scene Clips","type":"main","index":0}],[{"node":"Set: Fallback","type":"main","index":0}]]},"Code: Merge data from prior nodes with HTTP Output":{"main":[[{"node":"Set Fields: Define Outcome","type":"main","index":0}]]}}}


name: 💥🛠️Build a Web Search Chatbot with GPT-4o and MCP Brave Search
author_name: Joseph LePage
author_username: joe
categories: []
created_at: 2025-03-17T04:10:26.833Z
updated_at: 2025-03-17T04:10:26.833Z
url: https://n8n.io/workflows/3189
scraped_at: 2025-06-19 22:49:48
description:
  MCP AI Chatbot using Brave Search

  Disclaimer:  This workflow only works with local installations of n8n because it uses a community MCP node

  Who is this for?
  This workflow is ideal for developers, automation enthusiasts, and businesses looking to integrate AI-powered chat capabilities into their workflows. It's particularly useful for those leveraging Brave Search and MCP tools to enhance user interactions and streamline data retrieval.

  What problem is this workflow solving?
  This workflow addresses the challenge of creating an intelligent chatbot that can process user queries, execute searches using Brave Search, and provide responses enriched by AI. It simplifies the integration of multiple tools into a cohesive system, saving time and effort for users who need a robust conversational AI solution.

  What this workflow does
  Listens for incoming chat messages using the Chat Trigger node.
  Processes user input with an AI Agent powered by GPT-4o.
  Retrieves relevant tools using the MCP Get Brave Tools node.
  Executes specific search queries via the MCP Execute Brave Search node.
  Maintains short-term memory of conversations with the Simple Memory node.

  Setup
  Prerequisites:
     Access to an n8n instance (self-hosted).
     API credentials for OpenAI and MCP Client Tools.
     Brave Search API key.

  Steps:
     Import the workflow JSON into your n8n instance.
     Configure the API credentials for OpenAI and MCP Client Tools in their respective nodes.
     Set up your Brave Search API key in the MCP nodes. https://brave.com/search/api/

  Testing:
     Use the built-in chat interface to send test messages.
     Verify that the chatbot processes queries and returns results as expected.

  How to customize this workflow to your needs
  Modify the AI Agent's prompt settings to tailor responses to your specific use case.
  Adjust the memory buffer in the Simple Memory node to retain more or less conversational context.
  Replace or add additional tools in the MCP nodes to expand functionality.

nodes_used:
  ["@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryBufferWindow"]

workflow_json:
  {"id":"6MRJ2tfl8c2f3AuE","meta":{"instanceId":"31e69f7f4a77bf465b805824e303232f0227212ae922d12133a0f96ffeab4fef"},"name":"💥🛠️Build a Web Search Chatbot with GPT-4o and MCP Brave Search","tags":[],"nodes":[{"id":"b6e5eaa8-ddb3-4c13-8069-ce360bf4a945","name":"AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[240,-180],"parameters":{"options":{}},"typeVersion":1.8},{"id":"dde0154e-f7c2-4778-abcc-f79406db5e6b","name":"When chat message received","type":"@n8n/n8n-nodes-langchain.chatTrigger","position":[-260,-180],"webhookId":"68e54e15-548a-44df-ad06-7fb9e4e912a9","parameters":{"options":{}},"typeVersion":1.1},{"id":"877ce640-4d08-4ba7-b1d3-bcfc79600d2c","name":"MCP Get Brave Tools","type":"n8n-nodes-mcp.mcpClientTool","position":[200,280],"parameters":{},"credentials":{"mcpClientApi":{"id":"t2IDYWq0EcqBWvMA","name":"MCP Client (STDIO) account 2"}},"typeVersion":1},{"id":"fb3ce3c2-a809-43e5-92d0-82db0d78a971","name":"MCP Execute Brave Search","type":"n8n-nodes-mcp.mcpClientTool","position":[460,280],"parameters":{"toolName":"={{ $fromAI('tool', 'Set this with the specific tool name') }}","operation":"executeTool","toolParameters":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Tool_Parameters', ``, 'json') }}"},"credentials":{"mcpClientApi":{"id":"t2IDYWq0EcqBWvMA","name":"MCP Client (STDIO) account 2"}},"typeVersion":1},{"id":"357bde6a-66d0-48dc-972d-d0b35e3868ed","name":"Simple Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[-120,280],"parameters":{},"typeVersion":1.3},{"id":"3eba14c5-e4ed-4c4f-8f1d-2b5671b462cc","name":"gpt-4o","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-380,280],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"gpt-4o"},"options":{}},"credentials":{"openAiApi":{"id":"jEMSvKmtYfzAkhe6","name":"OpenAi account"}},"typeVersion":1.2},{"id":"781e5d92-6e9d-4874-93fc-5ea17d11f67f","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[120,160],"parameters":{"color":4,"height":280,"content":"## 1️⃣ MCP Get Brave Tools"},"typeVersion":1},{"id":"78a52697-352f-47ed-a7d2-3a65c9641fd7","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[380,160],"parameters":{"color":4,"height":280,"content":"## 2️⃣ MCP Execute Brave Search"},"typeVersion":1},{"id":"876003d5-7d90-4865-af36-3c0e504b02e7","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-200,160],"parameters":{"color":3,"height":280,"content":"## Short Term Chat Memory"},"typeVersion":1},{"id":"9f64f499-73d7-414f-a3d3-02c0417368a6","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-460,160],"parameters":{"color":5,"height":280,"content":"## Cloud LLM"},"typeVersion":1},{"id":"fc423452-832c-4377-9bde-04ab6d5c89aa","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-500,-400],"parameters":{"color":7,"width":1200,"height":920,"content":"# 💥🛠️Your First Simple MCP AI Chatbot using Brave Search\nhttps://github.com/nerding-io/n8n-nodes-mcp\nhttps://brave.com/search/api/"},"typeVersion":1},{"id":"5c6c7307-3283-4698-9104-c80df8a62888","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[80,40],"parameters":{"width":580,"height":440,"content":"## 🛠️ MCP Toolbox\nhttps://github.com/nerding-io/n8n-nodes-mcp\nhttps://brave.com/search/api/"},"typeVersion":1},{"id":"9d1bb515-f8fa-4d48-bbf5-c083f5efd89d","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[-360,-240],"parameters":{"color":4,"width":300,"height":240,"content":"## 👍Try Me!"},"typeVersion":1},{"id":"b093a455-aee7-4822-b079-7d9cbac783c2","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-1060,-400],"parameters":{"width":520,"height":1040,"content":"### **Who is this for?**\nThis workflow is ideal for developers, automation enthusiasts, and businesses looking to integrate AI-powered chat capabilities into their workflows. It's particularly useful for those leveraging Brave Search and MCP tools to enhance user interactions and streamline data retrieval.\n\n### **What problem is this workflow solving?**\nThis workflow addresses the challenge of creating an intelligent chatbot that can process user queries, execute searches using Brave Search, and provide responses enriched by AI. It simplifies the integration of multiple tools into a cohesive system, saving time and effort for users who need a robust conversational AI solution.\n\n### **What this workflow does**\n- Listens for incoming chat messages using the **Chat Trigger** node.\n- Processes user input with an **AI Agent** powered by GPT-4o.\n- Retrieves relevant tools using the **MCP Get Brave Tools** node.\n- Executes specific search queries via the **MCP Execute Brave Search** node.\n- Maintains short-term memory of conversations with the **Simple Memory** node.\n\n### **Setup**\n1. **Prerequisites**:\n   - Access to an n8n instance (self-hosted).\n   - API credentials for OpenAI and MCP Client Tools.\n   - Brave Search API key.\n\n2. **Steps**:\n   - Import the workflow JSON into your n8n instance.\n   - Configure the API credentials for OpenAI and MCP Client Tools in their respective nodes.\n   - Set up your Brave Search API key in the MCP nodes. https://brave.com/search/api/\n\n3. **Testing**:\n   - Use the built-in chat interface to send test messages.\n   - Verify that the chatbot processes queries and returns results as expected.\n\n### **How to customize this workflow to your needs**\n- Modify the AI Agent's prompt settings to tailor responses to your specific use case.\n- Adjust the memory buffer in the Simple Memory node to retain more or less conversational context.\n- Replace or add additional tools in the MCP nodes to expand functionality.\n"},"typeVersion":1},{"id":"8fb4f215-da26-43ad-b187-9b52ed6485ba","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[80,-280],"parameters":{"width":580,"height":280,"content":"## 🤖 AI Agent with Tools"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"a555f325-abd3-44bd-ac48-8b0f6910824e","connections":{"gpt-4o":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":0}]]},"Simple Memory":{"ai_memory":[[{"node":"AI Agent","type":"ai_memory","index":0}]]},"MCP Get Brave Tools":{"ai_tool":[[{"node":"AI Agent","type":"ai_tool","index":0}]]},"MCP Execute Brave Search":{"ai_tool":[[{"node":"AI Agent","type":"ai_tool","index":0}]]},"When chat message received":{"main":[[{"node":"AI Agent","type":"main","index":0}]]}}}


name: Analyze Any Website with OpenAI And Get On-Page SEO Audit
author_name: Not Another Marketer
author_username: notanothermarketer
categories: []
created_at: 2025-03-19T21:20:11.472Z
updated_at: 2025-03-19T21:20:11.472Z
url: https://n8n.io/workflows/3224
scraped_at: 2025-06-19 22:49:13
description:
  Instantly Find & Fix What’s Holding Your Page Back

  You’ve put in the work. Your content is strong. Your design is polished.

  But…

  ❌ Your page isn’t ranking where it should.
  ❌ Your competitors are outranking you—even with weaker content.
  ❌ You have no idea what’s wrong—or how to fix it.

  The truth? SEO isn’t just about keywords.

  Your technical setup, content structure, and on-page elements must work together seamlessly.
  And if anything is off? Google won’t rank your page.

  Who Is This For?
  SaaS Founders & Startups – Get higher rankings & organic traffic that converts.
  Marketing Teams & Agencies – Audit & optimize pages in seconds.
  E-commerce & Content Sites – Improve rankings for product pages, blogs, and landing pages.

  How It Works
  Paste your URL
  Get an instant audit + recommendations list
  Implement changes & watch your rankings jump

  The workflow scrapes the url you input, gets the htlm source code of the landing page, and sends it to OpenAI AI Agent.

  The Agent makes a deep analysis, audit the Technical + Content SEO of the page, and provides 10 Recommendations to improve your SEO.

  Setup Guide
  You will need OpenAI Credentials with an API Key to run the workflow.

  The workflow is using the OpenAI-o1 model to deliver the best results. It costs between $0.20/0.30 per run.

  You can adjust the prompt to your wish in the AI Agent parameters.

  Once the audit has been completed, it will send an email (don't forget to add your email address here)

  Below is an example of what you can expect

nodes_used:
  ["n8n-nodes-base.httpRequest","n8n-nodes-base.gmail","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi"]

workflow_json:
  {"id":"iLpBIRuhpWToO22N","meta":{"instanceId":"e8ec316b54e91908f34cbfdc330e5d1d5e97aa0ea8f7277c00d8a8a3892c9983","templateCredsSetupCompleted":true},"name":"🤖 On-Page SEO Audit","tags":[{"id":"TF9zcHoRnyCYBNVV","name":"SEO","createdAt":"2025-03-14T12:08:26.948Z","updatedAt":"2025-03-14T12:08:26.948Z"}],"nodes":[{"id":"f4a971be-a961-4ad6-b38d-830c5fca5407","name":"Landing Page Url","type":"n8n-nodes-base.formTrigger","position":[-180,0],"webhookId":"afe067a5-4878-4c9d-b746-691f77190f54","parameters":{"options":{},"formTitle":"Conversion Rate Optimizer","formFields":{"values":[{"fieldLabel":"Landing Page Url","placeholder":"https://yuzuu.co","requiredField":true}]},"formDescription":"Your Landing Page is Leaking Sales—Fix It Now"},"typeVersion":2.2},{"id":"e280139f-94b8-49dc-91e7-c6ffa0c04716","name":"Scrape Website","type":"n8n-nodes-base.httpRequest","position":[20,0],"parameters":{"url":"={{ $json['Landing Page Url'] }}","options":{}},"typeVersion":4.2},{"id":"de9ff0da-4ef9-4878-af0d-5733e010402c","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[320,20],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"MtyWeuRTqwi3Yx9H","name":"OpenAi account"}},"typeVersion":1.2},{"id":"25969781-4b1c-42ad-969c-efbb605be9e5","name":"OpenAI Chat Model1","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[360,400],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"MtyWeuRTqwi3Yx9H","name":"OpenAi account"}},"typeVersion":1.2},{"id":"0f135a2d-156c-43ee-b254-581c7d543a8c","name":"Content Audit","type":"@n8n/n8n-nodes-langchain.agent","position":[380,200],"parameters":{"text":"=You are the best SEO Manager in the country—a world-class expert in optimizing websites to rank on Google.\n\nIn this task, you will analyze the content of the webpage and perform a detailed and structured SEO Content Audit.\n\nAudit Structure\nYou will divide your audit in 2 parts:\n- The first part is the Analysis\n- The second is the Recommendations\n\nIn the Analysis, you will include:\n- Content Quality Assessment – Evaluate the content's overall quality, accuracy, and relevance to the target audience.\n- Keyword Research and Analysis – Identify primary and secondary keywords, keyword density, and keyword placement strategies.\n- Readability Analysis – Assess the content's readability score using metrics such as Flesch-Kincaid Grade Level, Flesch Reading Ease, and Gunning-Fog Index.\n\nIn the Recommendations, you will present your recommendations and actionable suggestions in clear, organized bullet points. Recommendations must improve the rankings in Google but also the user engagement. \n\nEnsure the output is properly formatted, clean, and highly readable. Do not include any introductory or explanatory text—only the audit findings.\n\nHere is the content of my landing page: {{ $json.data }}","options":{},"promptType":"define"},"typeVersion":1.7},{"id":"b693e35c-c0d4-4202-8c5e-2a5646a16cc4","name":"Technical Audit","type":"@n8n/n8n-nodes-langchain.agent","position":[380,-200],"parameters":{"text":"=You are the best SEO Manager in the country—a world-class expert in optimizing websites to rank on Google.\nIn this task, you will analyze the HTML code of a webpage and perform a detailed and structured On-Page Technical SEO Audit.\n\nAudit Structure\nYou will review all technical SEO aspects of the page. Once completed, you will present your findings and recommendations in clear, organized bullet points, categorized into three sections:\n- Critical Issues – Must be fixed immediately.\n- Quick Wins – Easy fixes with a big impact.\n- Opportunities for Improvement – Require more effort but offer potential benefits.\n\nEnsure the output is properly formatted, clean, and highly readable. Do not include any introductory or explanatory text—only the audit findings.\n\nHere is the content of my landing page: {{ $json.data }}","options":{},"promptType":"define"},"typeVersion":1.7},{"id":"3d172f93-7d94-4a43-9403-5cec799bbe47","name":"Merge","type":"n8n-nodes-base.merge","position":[880,0],"parameters":{},"typeVersion":3,"alwaysOutputData":true},{"id":"2081bf62-0e47-497e-8a3e-d30d330f6a9d","name":"Aggregate","type":"n8n-nodes-base.aggregate","position":[1080,0],"parameters":{"options":{},"fieldsToAggregate":{"fieldToAggregate":[{"fieldToAggregate":"output"}]}},"typeVersion":1},{"id":"e1cfc16e-e0dc-4298-9b94-ffb7f23b45aa","name":"Markdown","type":"n8n-nodes-base.markdown","position":[1280,0],"parameters":{"mode":"markdownToHtml","options":{},"markdown":"=# On-Page Technical Audit\n{{ $json.output[0] }}\n\n# On-Page SEO Content Audit\n{{ $json.output[1] }}"},"typeVersion":1},{"id":"7dc41215-e276-439c-be11-92278b1c3a60","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[1360,-160],"parameters":{"color":3,"width":360,"height":100,"content":"## Send Email \nConnect your credentials & Easily send emails from a Gmail address. "},"typeVersion":1},{"id":"28aea6bd-beef-4116-97c2-e8b88e96d5ac","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[320,-380],"parameters":{"color":3,"width":420,"height":140,"content":"## Open AI Setup\n- Add your credentials\n- Select o1 model for (way) better results. \n- One run = one page audit = around $0.3 with o1"},"typeVersion":1},{"id":"3242a0c3-4439-4ad1-8185-47185046080d","name":"Gmail","type":"n8n-nodes-base.gmail","position":[1480,0],"webhookId":"2979e4dc-1689-447e-8cd4-eb907b4eedf4","parameters":{"sendTo":"hello@youremail.com","message":"={{ $json.data }}","options":{},"subject":"=On-Page SEO Audit -  {{ $('Landing Page Url').item.json['Landing Page Url'] }}"},"credentials":{"gmailOAuth2":{"id":"9EELWJ0jA3PIbx13","name":"Gmail account"}},"typeVersion":2.1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"bc4ac79c-71a0-4dae-805d-55b682b0c199","connections":{"Merge":{"main":[[{"node":"Aggregate","type":"main","index":0}]]},"Markdown":{"main":[[{"node":"Gmail","type":"main","index":0}]]},"Aggregate":{"main":[[{"node":"Markdown","type":"main","index":0}]]},"Content Audit":{"main":[[{"node":"Merge","type":"main","index":1}]]},"Scrape Website":{"main":[[{"node":"Content Audit","type":"main","index":0},{"node":"Technical Audit","type":"main","index":0}]]},"Technical Audit":{"main":[[{"node":"Merge","type":"main","index":0}]]},"Landing Page Url":{"main":[[{"node":"Scrape Website","type":"main","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Technical Audit","type":"ai_languageModel","index":0}]]},"OpenAI Chat Model1":{"ai_languageModel":[[{"node":"Content Audit","type":"ai_languageModel","index":0}]]}}}


name: 🔍🛠️Generate SEO-Optimized WordPress Content with AI Powered Perplexity Research
author_name: Joseph LePage
author_username: joe
categories: []
created_at: 2025-03-23T02:02:14.835Z
updated_at: 2025-03-23T02:02:14.835Z
url: https://n8n.io/workflows/3291
scraped_at: 2025-06-19 22:49:05
description:
  Generate SEO-Optimized WordPress Content with Perplexity Research

  Who is This For?
  This workflow is ideal for content creators, marketers, and businesses looking to streamline the creation of SEO-optimized blog posts for WordPress. It is particularly suited for professionals in the AI consulting and workflow automation industries.

  What Problem Does This Workflow Solve?
  Creating high-quality, SEO-friendly blog posts can be time-consuming and challenging, especially when trying to balance research, formatting, and publishing. This workflow automates the process by integrating research capabilities, AI-driven content creation, and seamless WordPress publishing. It reduces manual effort while ensuring professional-grade output.

  What This Workflow Does
  Research: Gathers detailed insights from Perplexity AI based on user-provided queries.
  Content Generation: Uses OpenAI models to create structured blog posts, including titles, slugs, meta descriptions, and HTML content optimized for WordPress.
  Image Handling: Automatically fetches and uploads featured images to WordPress posts.
  Publishing: Drafts the blog post directly in WordPress with all necessary formatting and metadata.
  Notification: Sends a success message via Telegram upon completion.

  Setup Guide
  Prerequisites:
     A WordPress account with API access.
     OpenAI API credentials.
     Perplexity AI API credentials.
     Telegram bot credentials for notifications.

  Steps:
     Import the workflow into your n8n instance.
     Configure API credentials for WordPress, OpenAI, Perplexity AI, and Telegram.
     Customize the form trigger to define your research query.
     Test the workflow using sample queries to ensure smooth execution.

  How to Customize This Workflow to Your Needs
  Modify the research query prompt in the "Form Trigger" node to suit your industry or niche.
  Adjust content generation guidelines in the "Copywriter AI Agent" node for specific formatting preferences.
  Replace the image URL in the "Set Image URL" node with your own source or dynamic image selection logic.

nodes_used:
  ["n8n-nodes-base.httpRequest","n8n-nodes-base.telegram","n8n-nodes-base.wordpress","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.outputParserStructured","@n8n/n8n-nodes-langchain.openAi"]

workflow_json:
  {"id":"5lMPjSDuoMvCJnko","meta":{"instanceId":"31e69f7f4a77bf465b805824e303232f0227212ae922d12133a0f96ffeab4fef","templateCredsSetupCompleted":true},"name":"🔍🛠️Generate SEO-Optimized WordPress Content with Perplexity Research","tags":[],"nodes":[{"id":"17ab0b24-b1eb-4e4e-a249-9889c9876fe4","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-1440,460],"parameters":{"color":3,"width":420,"height":440,"content":"## Write SEO Optimized Blog Post\n\n\n"},"typeVersion":1},{"id":"0931aacf-5c47-4bb0-86b6-158c2c7470b1","name":"Wordpress","type":"n8n-nodes-base.wordpress","position":[-1220,1120],"parameters":{"title":"={{ $('Combine Blog Details').item.json.data[2].output.title }}","additionalFields":{"slug":"={{ $('Combine Blog Details').item.json.data[2].output.slug }}","status":"draft","sticky":false,"content":"={{ $json.content }}","authorId":2,"postTemplate":{"values":{}},"commentStatus":"closed"}},"credentials":{"wordpressApi":{"id":"50Ph69y0TPKvO9tn","name":"Wordpress"}},"typeVersion":1},{"id":"81329ff1-b26a-499c-bd82-fd334503ab4f","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-980,220],"parameters":{"color":7,"width":440,"height":280,"content":"## Create HTML\n\n\n"},"typeVersion":1},{"id":"03de9f23-e5ec-483b-a3dd-97617bd5165d","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[-1320,1020],"parameters":{"color":4,"width":300,"height":280,"content":"## Post on Wordpress\n\n\n"},"typeVersion":1},{"id":"6bf602e0-ad29-47e6-93d7-79fd2a4228c2","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-900,820],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"jEMSvKmtYfzAkhe6","name":"OpenAi account"}},"typeVersion":1.2},{"id":"8a3739ac-9492-400c-b5b8-eeb305647752","name":"Structured Output Parser","type":"@n8n/n8n-nodes-langchain.outputParserStructured","position":[-680,820],"parameters":{"jsonSchemaExample":"{\n\"slug\": \"rpo-benefits-recruitment\",\n\"title\": \"7 Key Advantages of RPO for Modern Recruitment\",\n\"meta\": \"Explore how Recruitment Process Outsourcing (RPO) enhances hiring efficiency, reduces costs, and expands talent pools for businesses seeking top candidates.\"\n}"},"typeVersion":1.2},{"id":"af02ee94-4c26-4be5-bd21-09e020bff876","name":"Create Title, Slug, Meta","type":"@n8n/n8n-nodes-langchain.agent","position":[-880,640],"parameters":{"text":"=**Create a slug, blog post title, and meta description for the following blog post:**\n\n{{ $json.output }}\n\n**Slug Guidelines:**\n- Keep it concise (4-5 words maximum).\n- Include the primary keyword related to recruitment or HR.\n- Use hyphens to separate words.\n- Avoid unnecessary words, articles, or prepositions.\n- Ensure it reflects the main topic of the blog post.\n- Make it readable and relevant for both users and search engines.\n\n**Title Guidelines:**\n- Avoid AI words like \"Transform\" or \"Revolutionize\" and similar overused terms.\n- Avoid using a colon (:) in the title.\n- Never structure it as a primary/secondary title separated by a colon.\n- Include the primary keyword related to recruitment or HR (e.g., 'AI in recruitment' or 'talent acquisition trends').\n- Clearly inform users what they can expect from reading the blog post.\n- Be concise and engaging, ideally 50-60 characters long.\n- Incorporate power words that appeal to HR professionals and recruiters.\n\n**Meta Description Guidelines:**\n- Avoid AI words like \"Transform\" or \"Revolutionize\" and similar overused terms.\n- Be concise: Limit to 150-160 characters to ensure full visibility in search results.\n- Include keywords: Naturally incorporate primary recruitment-related keywords to enhance relevance and visibility.\n- Provide value: Clearly convey the benefits or insights readers will gain from the article.\n- Be engaging: Use action-oriented language or a thought-provoking question to encourage clicks.\n- Align with content: Accurately reflect the blog post's content to meet user expectations and reduce bounce rates.\n- Highlight expertise: Subtly emphasize SocialFind's authority in the recruitment field.\n\nYour output must be a single valid JSON object with these 3 fields:\n-slug: The slug\n-title: The blog post title\n-meta: The meta description  \n\nEach should be presented without any additional text, explanation, quotation marks, or formatting.\n","options":{},"promptType":"define","hasOutputParser":true},"typeVersion":1.8},{"id":"115c4043-6fda-42a4-ac3c-c7979b2f327e","name":"Create HTML","type":"@n8n/n8n-nodes-langchain.openAi","position":[-880,300],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"GPT-4O-MINI"},"options":{},"messages":{"values":[{"content":"=Only output the HTML content without preamble or further explanation. Generate WordPress-compatible HTML for a blog post based on the provided content.\n\n### CONTENT PROCESSING:\n- Process all content from {{ $json.output }}\n- Preserve all original facts, information, and URLs\n- Format according to the specifications below\n\n### REQUIRED STRUCTURE (IN THIS ORDER):\n1. Title (H2)\n2. Estimated reading time\n3. Key takeaways (3-5 bullet points)\n4. Table of contents (linked to all headings)\n5. Main content (with proper heading hierarchy)\n6. FAQ section\n\n### STYLING REQUIREMENTS:\n- Style Override: Include a style section with !important declarations\n- Links: All hyperlinks, TOC items, and FAQ questions must be #00c2ff (blue)\n- Headings: All headings need a bottom border in #00c2ff with padding\n- Spacing: Add <br><br> between each major section\n\n### ENGAGEMENT FORMATTING:\n- Use bold, italics, bullet points, quotes, and highlighting for emphasis\n- Create proper paragraph structure with appropriate line breaks\n- NO emojis allowed\n- Use whitespace strategically for readability\n\n### HYPERLINK HANDLING (CRITICAL):\n- When URLs appear next to keyphrases (e.g., \"AI tools (https://example.com)\")\n- Convert to: <a href=\"https://example.com\" style=\"color: #00c2ff !important;\">AI tools</a>\n- The KEYPHRASE must be linked, never the URL itself\n\n### WORDPRESS COMPATIBILITY:\n- Use WordPress block classes (wp-block-heading, wp-block-paragraph, etc.)\n- Add heading IDs starting with \"h-\" for better TOC linking\n- Ensure all styles use !important to override theme styles\n\nDO NOT include any explanations, code tags, or comments. Output ONLY the raw HTML.\n"}]}},"credentials":{"openAiApi":{"id":"jEMSvKmtYfzAkhe6","name":"OpenAi account"}},"typeVersion":1.8},{"id":"4756c8f2-406e-4a56-adb0-0c4708dabe6a","name":"Merge","type":"n8n-nodes-base.merge","position":[-420,560],"parameters":{"numberInputs":3},"typeVersion":3},{"id":"1205aecf-08a1-499d-ac9e-822dd66b295f","name":"Upload Image to Wordpress","type":"n8n-nodes-base.httpRequest","position":[-520,1120],"parameters":{"url":"https://commonclone.com/wp-json/wp/v2/media","method":"POST","options":{},"sendBody":true,"contentType":"binaryData","sendHeaders":true,"authentication":"predefinedCredentialType","headerParameters":{"parameters":[{"name":"Content-Disposition","value":"=attachment; filename=\"cover-image-{{ $('Wordpress').item.json.id }}.jpeg\""}]},"inputDataFieldName":"data","nodeCredentialType":"wordpressApi"},"credentials":{"wordpressApi":{"id":"50Ph69y0TPKvO9tn","name":"Wordpress CommonClone.com RazorCX"}},"typeVersion":4.2},{"id":"b4437d9e-8b90-4d15-a96d-46645618a56d","name":"Set Image on Wordpress Post","type":"n8n-nodes-base.httpRequest","position":[-320,1120],"parameters":{"url":"=https://commonclone.com/wp-json/wp/v2/posts/{{ $('Wordpress').item.json.id }}","method":"POST","options":{},"sendQuery":true,"authentication":"predefinedCredentialType","queryParameters":{"parameters":[{"name":"featured_media","value":"={{ $json.id }}"}]},"nodeCredentialType":"wordpressApi"},"credentials":{"wordpressApi":{"id":"50Ph69y0TPKvO9tn","name":"Wordpress CommonClone.com RazorCX"}},"typeVersion":4.2},{"id":"bf05eaf3-2522-488e-893d-1ed9b2ed88b2","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-1940,460],"parameters":{"color":4,"width":460,"height":300,"content":"## Perplexity Research\n\n\n"},"typeVersion":1},{"id":"22e8c044-ed98-495a-957e-c5e3fecc2b7d","name":"On form submission","type":"n8n-nodes-base.formTrigger","position":[-2120,560],"webhookId":"a29cbcd3-9d11-4f7c-9aad-14681c356c53","parameters":{"options":{},"formTitle":"Blog Factory","formFields":{"values":[{"fieldType":"textarea","fieldLabel":"Research Query","placeholder":"=What are the most common challenges facing Canadian employers regarding recruitment and why would they want to hire a recruiting firm to solve these problems.","requiredField":true}]},"formDescription":"Create SEO optimized blog posts"},"typeVersion":2.2},{"id":"6e6d4952-793f-4dc5-8d29-219d420149a9","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-1940,800],"parameters":{"width":460,"height":500,"content":"## Sample Generic Search Terms\nAdd your own or try these for your specific geo location.\n\n1. **Severe skills shortages in healthcare, construction, and education sectors.**  \n2. **Aging workforce widens employment gaps in key industries.**  \n3. **Tight labor market with 110 vacancies per 100 unemployed people.**  \n4. **High demand for specialized skills due to economic changes.**  \n5. **Housing shortages deter international candidates from relocating to the Netherlands.**  \n6. **Strict employment regulations complicate hiring processes for non-EU workers.**  \n7. **Intense competition for talent due to low unemployment rates.**  \n8. **Mismatch between available talent and job-specific skill requirements.**  \n9. **Candidates expect high benefits packages, increasing recruitment costs significantly.**  \n10. **Difficulty navigating compliance and labor laws for international hiring processes.**"},"typeVersion":1},{"id":"bb94017e-dc2a-43e3-ae5c-1f3227b1f0ef","name":"Perplexity Research","type":"n8n-nodes-base.httpRequest","position":[-1860,560],"parameters":{"url":"https://api.perplexity.ai/chat/completions","method":"POST","options":{},"jsonBody":"={\n  \"model\": \"sonar-pro\",\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"Act as a professional news researcher who is capable of finding detailed summaries about a news topic from highly reputable sources.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \" Research the following topic and return everything you can find about: '{{ $json['Research Query'] }}'.\"\n    }\n  ]\n}\n","sendBody":true,"specifyBody":"json","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"05RfNG280MisTyPP","name":"Perplexity"}},"typeVersion":4.2},{"id":"66086876-4b49-45fe-aecc-f7f062a59dba","name":"Cleanup Links","type":"n8n-nodes-base.set","position":[-1660,560],"parameters":{"options":{},"assignments":{"assignments":[{"id":"23b8e8c4-9191-415a-9661-1b60d413528a","name":"research","type":"string","value":"={{ $json.choices[0].message.content.replaceAll(\"[1]\", \" - source: \" +$json.citations[0]).replaceAll(\"[2]\",\" - source:\" +$json.citations[1]).replaceAll(\"[3]\",\" - source: \" +$json.citations[2]).replaceAll(\"[4]\",\" - source: \"+$json.citations[3]).replaceAll(\"[5]\",\" - source: \"+$json.citations[4]).replaceAll(\"[6]\",\" - source: \"+$json.citations[5]).replaceAll(\"[7]\",\" - source: \"+$json.citations[6]).replaceAll(\"[8]\",\" - source: \"+$json.citations[7]).replaceAll(\"[9]\",\" - source: \"+$json.citations[8]).replaceAll(\"[10]\",\" - source: \"+$json.citations[9]) }}"}]}},"typeVersion":3.4},{"id":"f81c9505-111f-473a-94b6-c79364410810","name":"Copywriter AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[-1360,560],"parameters":{"text":"=You are part of a marketing team that creates high-quality blog posts for the AI consulting and workflow automation industry based in Canada. Your goal is to produce engaging, SEO-optimized content that positions the company as an authority in the AI consulting industry and attracts inbound leads.\n\nEvery 2 days, your team posts a blog on the most trending topics in AI consulting and n8n workflows. As the copywriter, you are provided with the following information:\n\n- Query: The main topic for this week's blog post, representing the most trending news in the recruitment space.\n\n- Other keywords: A list of high-search-volume keywords related to AI consulting and n8n workflows. Incorporate these naturally into the blog post where relevant, without forcing them or changing the post's meaning.\n\n- Research findings: Detailed information from reputable sources related to the blog topic. Your post must be based on this research.\n\nGiven this information, write a comprehensive blog post that:\n\n- Includes the query in the blog title, H2 header, and early in the introduction.\n- Incorporates all details from the research findings, including source URLs for potential hyperlinks.\n- Is detailed and informative, showcasing the companies expertise in AI consulting and n8n workflows to automate business processes.\n- Uses a professional yet engaging tone, highlighting the exciting developments and challenges in the recruitment industry.\n- Flows naturally and logically, making it easy for readers to follow.\n- Is between 1500 to 2000 words long.\n- Is written at a level accessible to HR professionals and business leaders.\n\nAdditional requirements:\n- Include practical takeaways or actionable advice for recruiters and HR professionals.\n- Highlight how the topic relates to the companies services or expertise.\n- Include a call-to-action (CTA) that encourages readers to explore the comapnies services or contact for more information.\n\nCreate the entire blog post draft in your first output. Don't stop or cut it short.\n\nYour output must be the blog post and nothing else.\n\nHere are the details of this blog post project:\n\nQuery:\n{{ $('On form submission').item.json['Research Query'] }}\n\nDetailed Research:\n{{ $('Cleanup Links').item.json.research }}\n\n\n","options":{},"promptType":"define"},"typeVersion":1.8},{"id":"1ee6bb8f-6441-4ed9-83e0-d0839b2d0e01","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[-980,540],"parameters":{"color":7,"width":440,"height":440,"content":"## Create Title, Slug & Meta\n\n\n"},"typeVersion":1},{"id":"cc53a2af-ef22-446b-a9ee-b6f4ee649865","name":"Cleanup HTML ","type":"n8n-nodes-base.set","position":[-220,820],"parameters":{"options":{},"assignments":{"assignments":[{"id":"0afb2988-1481-4b04-b16d-fb33c50a16d0","name":"content","type":"string","value":"={{ $json.data[0].message.content.replaceAll('```html', '').replaceAll('```','') }}"}]}},"typeVersion":3.4},{"id":"b31c8afe-e402-49c4-ba49-ee418cecc44e","name":"GET Image","type":"n8n-nodes-base.httpRequest","position":[-720,1120],"parameters":{"url":"={{ $json['image-url'] }}","options":{}},"typeVersion":4.2},{"id":"1089466a-1307-4f22-a242-d324c9165379","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-980,1020],"parameters":{"width":820,"height":280,"content":"## Set Image for Wordpress Post"},"typeVersion":1},{"id":"288e212b-5aa5-452e-87d6-ae06c6ad062a","name":"Set Image URL","type":"n8n-nodes-base.set","position":[-920,1120],"parameters":{"options":{},"assignments":{"assignments":[{"id":"1f0541df-05ab-4e3d-a5d8-3904579fc8a9","name":"image-url","type":"string","value":"=https://smartcdn.gprod.postmedia.digital/healthing/wp-content/uploads/2024/07/GettyImages-1455799246.jpg?quality=90&strip=all&w=704&h=395"}]}},"typeVersion":3.4},{"id":"38bf38e5-888e-4d63-a48e-e6affab28158","name":"Send Success Message to Telegram","type":"n8n-nodes-base.telegram","position":[-80,1120],"webhookId":"91f7d710-450a-4b66-8e46-82f53492351e","parameters":{"text":"=Success! Your blog post was created at {{ $now }}","chatId":"={{ $env.TELEGRAM_CHAT_ID }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"pAIFhguJlkO3c7aQ","name":"Telegram account"}},"typeVersion":1.2},{"id":"30f0fa84-9918-4bf6-86e4-ef8f1dcf079c","name":"gpt-4o-mini","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-1360,760],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"jEMSvKmtYfzAkhe6","name":"OpenAi account"}},"typeVersion":1.2},{"id":"d2d83cc5-1502-4b04-ac12-0bb351a90e58","name":"Combine Blog Details","type":"n8n-nodes-base.aggregate","position":[-220,560],"parameters":{"options":{},"aggregate":"aggregateAllItemData"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"4209c818-8b02-453e-9254-c70bde66f743","connections":{"Merge":{"main":[[{"node":"Combine Blog Details","type":"main","index":0}]]},"GET Image":{"main":[[{"node":"Upload Image to Wordpress","type":"main","index":0}]]},"Wordpress":{"main":[[{"node":"Set Image URL","type":"main","index":0}]]},"Create HTML":{"main":[[{"node":"Merge","type":"main","index":0}]]},"gpt-4o-mini":{"ai_languageModel":[[{"node":"Copywriter AI Agent","type":"ai_languageModel","index":0}]]},"Cleanup HTML ":{"main":[[{"node":"Wordpress","type":"main","index":0}]]},"Cleanup Links":{"main":[[{"node":"Copywriter AI Agent","type":"main","index":0}]]},"Set Image URL":{"main":[[{"node":"GET Image","type":"main","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Create Title, Slug, Meta","type":"ai_languageModel","index":0}]]},"On form submission":{"main":[[{"node":"Perplexity Research","type":"main","index":0}]]},"Copywriter AI Agent":{"main":[[{"node":"Create HTML","type":"main","index":0},{"node":"Create Title, Slug, Meta","type":"main","index":0},{"node":"Merge","type":"main","index":1}]]},"Perplexity Research":{"main":[[{"node":"Cleanup Links","type":"main","index":0}]]},"Combine Blog Details":{"main":[[{"node":"Cleanup HTML ","type":"main","index":0}]]},"Create Title, Slug, Meta":{"main":[[{"node":"Merge","type":"main","index":2}]]},"Structured Output Parser":{"ai_outputParser":[[{"node":"Create Title, Slug, Meta","type":"ai_outputParser","index":0}]]},"Upload Image to Wordpress":{"main":[[{"node":"Set Image on Wordpress Post","type":"main","index":0}]]},"Set Image on Wordpress Post":{"main":[[{"node":"Send Success Message to Telegram","type":"main","index":0}]]}}}


name: AI-Powered Research Assistant for Platform Questions with GPT-4o and MCP
author_name: Onur
author_username: onurpolat05
nodes_used: ["@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi"]
categories: []
created_at: 2025-03-24T09:42:01.239Z
updated_at: 2025-03-24T09:42:01.239Z
url: https://n8n.io/workflows/3303
scraped_at: 2025-06-19 22:49:56
description:
  Description

  This workflow empowers you to effortlessly get answers to your n8n platform questions through an AI-powered assistant. Simply send your query, and the assistant will search documentation, forum posts, and example workflows to provide comprehensive, accurate responses tailored to your specific needs.

  &gt; Note: This workflow uses community nodes (n8n-nodes-mcp.mcpClientTool) and will only work on self-hosted n8n instances. You'll need to install the required community nodes before importing this workflow.

  !

  What does this workflow do?

  This workflow streamlines the information retrieval process by automatically researching n8n platform documentation, community forums, and example workflows, providing you with relevant answers to your questions.

  Who is this for?

  New n8n Users**: Quickly get answers to basic platform questions and learn how to use n8n effectively
  Experienced Developers**: Find solutions to specific technical issues or discover advanced workflows
  Teams**: Boost productivity by automating the research process for n8n platform questions
  Anyone** looking to leverage AI for efficient and accurate n8n platform knowledge retrieval

  Benefits

  Effortless Research**: Automate the research process across n8n documentation, forum posts, and example workflows
  AI-Powered Intelligence**: Leverage the power of LLMs to understand context and generate helpful responses
  Increased Efficiency**: Save time and resources by automating the research process
  Quick Solutions**: Get immediate answers to your n8n platform questions
  Enhanced Learning**: Discover new workflows, features, and best practices to improve your n8n experience

  How It Works

  Receive Request: The workflow starts when a chat message is received containing your n8n-related question
  AI Processing: The AI agent powered by OpenAI GPT-4o analyzes your question
  Research and Information Gathering: The system searches across multiple sources:
     Official n8n documentation for general knowledge and how-to guides
     Community forums for bug reports and specific issues
     Example workflow repository for relevant implementations
  Response Generation: The AI agent compiles the research and generates a clear, comprehensive answer
  Output: The workflow provides you with the relevant information and step-by-step guidance when applicable

  n8n Nodes Used

  When chat message received (Chat Trigger)
  OpenAI Chat Model (GPT-4o mini)
  N8N AI Agent
  n8n-assistant tools (MCP Client Tool - Community Node)
  n8n-assistant execute (MCP Client Tool - Community Node)

  Prerequisites

  Self-hosted n8n instance
  OpenAI API credentials
  MCP client community node installed
  MCP server configured to search n8n resources

  Setup

  Import the workflow JSON into your n8n instance
  Configure the OpenAI credentials
  Configure your MCP client API credentials
  In the n8n-assistant execute node, ensure the parameter is set to "specific" (corrected from "spesific")
  Test the workflow by sending a message with an n8n-related question

  MCP Server Connection

  To connect to the MCP server that powers this assistant's research capabilities, you need to use the following URL:
  https://smithery.ai/server/@onurpolat05/n8n-assistant

  This MCP server is specifically designed to search across three types of n8n resources:
  Official documentation for general platform information and workflow creation guidance
  Community forums for bug-related issues and troubleshooting
  Example workflow repositories for reference implementations

  Configure this URL in your MCP client credentials to enable the assistant to retrieve relevant information based on user queries.

  This workflow combines the convenience of chat with the power of AI to provide a seamless n8n platform research experience. Start getting instant answers to your n8n questions today!

workflow_json:
  {"meta":{"instanceId":"02e782574ebb30fbddb2c3fd832c946466d718819d25f6fe4b920124ff3fc2c1","templateCredsSetupCompleted":true},"nodes":[{"id":"bc58bd73-921a-445c-a905-6f1bbbc0e9c3","name":"When chat message received","type":"@n8n/n8n-nodes-langchain.chatTrigger","position":[1160,420],"webhookId":"cf762550-98e7-42f0-a0f3-cd9594331c00","parameters":{"options":{}},"typeVersion":1.1},{"id":"308aea70-2831-4abd-90f6-d4cbf3901be4","name":"n8n Research AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[1440,420],"parameters":{"options":{"systemMessage":"You are an assistant integrated with the n8n Multi-Channel Platform (MCP). Your primary role is to interact with the MCP to retrieve available tools and content based on user queries about n8n. When a user asks for information or assistance regarding n8n, first send a request to the MCP to fetch the relevant tools and content. Analyze the retrieved data to understand the available options, then create a tailored response that addresses their specific needs regarding n8n functionalities, documentation, forum posts, or example workflows. Ensure that your responses are clear, actionable, and directly related to the user's queries about n8n."}},"typeVersion":1.8},{"id":"94cb78f5-3520-4432-b3c9-0524411113e9","name":"n8n-assistant Tool Lookup","type":"n8n-nodes-mcp.mcpClientTool","position":[1500,640],"parameters":{},"credentials":{"mcpClientApi":{"id":"w1ZOoPXYGz6W2g1T","name":"n8n-assistant"}},"typeVersion":1},{"id":"78a87949-afda-4c52-ae9f-f8d343fb6567","name":"n8n-assistant Execute Tool","type":"n8n-nodes-mcp.mcpClientTool","position":[1700,640],"parameters":{"toolName":"={{$fromAI(\"tool\",\"Set this specific tool name\")}}","operation":"executeTool","toolParameters":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Tool_Parameters', ``, 'json') }}"},"credentials":{"mcpClientApi":{"id":"w1ZOoPXYGz6W2g1T","name":"n8n-assistant"}},"typeVersion":1},{"id":"cc1619ec-6f49-45e6-8a7b-440da7ee5bc5","name":"OpenAI Chat Model2","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[1320,640],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"q2i0xAiFxUOYOlJ0","name":"OpenAI_BCP"}},"typeVersion":1.2}],"pinData":{},"connections":{"OpenAI Chat Model2":{"ai_languageModel":[[{"node":"n8n Research AI Agent","type":"ai_languageModel","index":0}]]},"n8n-assistant Tool Lookup":{"ai_tool":[[{"node":"n8n Research AI Agent","type":"ai_tool","index":0}]]},"When chat message received":{"main":[[{"node":"n8n Research AI Agent","type":"main","index":0}]]},"n8n-assistant Execute Tool":{"ai_tool":[[{"node":"n8n Research AI Agent","type":"ai_tool","index":0}]]}}}


name: WebSecScan: AI-Powered Website Security Auditor
author_name: Dale Dunlop
author_username: daledunlop
categories: []
created_at: 2025-03-24T18:13:24.596Z
updated_at: 2025-03-24T18:13:24.596Z
url: https://n8n.io/workflows/3314
scraped_at: 2025-06-19 22:50:08
description:
  WebSecScan: AI-Powered Website Security Auditor

  This n8n workflow provides comprehensive website security analysis by leveraging OpenAI's models to detect vulnerabilities, configuration issues, and security misconfigurations. The workflow generates a professional HTML security report delivered directly via Gmail.

  Key Features

  Dual-Layer Security Analysis:** Performs parallel security audits using specialized OpenAI agents:
    Header Configuration Audit: Analyzes HTTP headers, CORS policies, CSP implementation, and cookie security
    Vulnerability Assessment: Identifies XSS vectors, information disclosure, and client-side weaknesses
    
  Detailed Security Grading:** Automatically calculates a security grade (A+ to F) based on findings severity and quantity

  Professional Report Generation:** Creates a comprehensive HTML report with:
    Security grade visualization
    Color-coded vulnerability categories
    Detailed recommendations with example configuration fixes
    Header presence/absence indicators
    Implementation guidance for remediation

  Non-Invasive Testing:** Performs analysis without active scanning or exploitation attempts

  Technical Implementation

  Multi-Agent Architecture:** Utilizes two specialized OpenAI agents with custom prompts tailored for security analysis
  Advanced Header Analysis:** Detects presence and proper implementation of critical security headers:
    Content-Security-Policy
    Strict-Transport-Security
    X-Content-Type-Options
    X-Frame-Options
    Referrer-Policy
    Permissions-Policy

  Intelligent Issue Detection:** Uses JavaScript processing to analyze OpenAI outputs and count critical/warning issues
  Responsive HTML Report:** Dynamically generates a mobile-friendly report with detailed findings and recommendations

  Setup Requirements

  1. OpenAI API Configuration
  Create an OpenAI API key at platform.openai.com
  In n8n, go to Settings → Credentials → New → OpenAI API
  Enter your API key and save

  2. Gmail Integration
  Navigate to Settings → Credentials → New → Gmail OAuth2 API
  Complete the OAuth authentication flow
  Configure recipient email in the "Send Security Report" node

  3. Workflow Customization (Optional)
  Modify the form title/description in the Landing Page node
  Upgrade from gpt-4o-mini to gpt-4o for more comprehensive analysis
  Add additional recipients to the email report

  Usage Instructions

  Activate the workflow and access the form via the generated URL
  Enter any website URL to analyze (including the http:// or https:// prefix)
  Receive a detailed security report via email within minutes
  Share findings with your development team to implement fixes

  This workflow represents a non-invasive security assessment tool. For production environments, complement with professional penetration testing services.

nodes_used:
  ["n8n-nodes-base.httpRequest","n8n-nodes-base.gmail","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi"]

workflow_json:
  {"meta":{"instanceId":"c2589fa234defe76e8a1321c3a7d0a73579d0120d64d927e88f5e3be584ae8d4"},"nodes":[{"id":"634f2fc5-0ba7-42ad-bdf5-ade3415dd288","name":"Landing Page Url","type":"n8n-nodes-base.formTrigger","position":[-200,580],"webhookId":"afe067a5-4878-4c9d-b746-691f77190f54","parameters":{"options":{},"formTitle":"Website Security Scanner","formFields":{"values":[{"fieldLabel":"Landing Page Url","placeholder":"https://example.com","requiredField":true}]},"formDescription":"Check your website for security vulnerabilities and get a detailed report"},"typeVersion":2.2},{"id":"6cee63ca-d0f6-444a-b882-22da1a9fd70c","name":"Scrape Website","type":"n8n-nodes-base.httpRequest","position":[0,580],"parameters":{"url":"={{ $json['Landing Page Url'] }}","options":{"redirect":{"redirect":{"maxRedirects":5}},"response":{"response":{"fullResponse":true,"responseFormat":"text"}}}},"typeVersion":4.2},{"id":"0d5d1e76-e627-4565-a1ee-6a610f4b2028","name":"OpenAI Headers Analysis","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[340,600],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"yZ0AIg9abV8HJadB","name":"OpenAi account"}},"typeVersion":1.2},{"id":"04427ef7-515d-4a1a-88d2-ade10aeefc87","name":"OpenAI Content Analysis","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[340,980],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"yZ0AIg9abV8HJadB","name":"OpenAi account"}},"typeVersion":1.2},{"id":"d4ee4db8-aa04-4068-9b97-d16acf98c027","name":"Security Vulnerabilities Audit","type":"@n8n/n8n-nodes-langchain.agent","position":[360,780],"parameters":{"text":"=You are an elite cybersecurity expert specializing in web application security.\n\nIn this task, you will analyze the HTML and visible content of the webpage to identify potential security vulnerabilities.\n\nAudit Structure\nYou will review all client-side security aspects of the page and present your findings in three sections:\n- Critical Vulnerabilities – Issues that could lead to immediate compromise\n- Information Leakage – Sensitive data exposed in page source\n- Client-Side Weaknesses – JavaScript vulnerabilities, XSS opportunities, etc.\n\nFor each issue found, provide:\n1. A clear description of the vulnerability\n2. The potential impact\n3. A specific recommendation to fix it\n\nIf you find no issues in a particular section, explicitly state that no issues were found in that category.\n\nEnsure the output is properly formatted, clean, and highly readable. Focus only on issues that can be detected from the client-side code.\n\nHere is the content of the webpage: {{ $json.data }}","options":{},"promptType":"define"},"typeVersion":1.7},{"id":"c9702f2b-845b-464d-9c32-3d5be308ef77","name":"Security Configuration Audit","type":"@n8n/n8n-nodes-langchain.agent","position":[360,380],"parameters":{"text":"=You are an elite web security expert specializing in secure configurations.\n\nIn this task, you will analyze the HTTP headers, cookies, and overall configuration of a webpage to identify security misconfigurations.\n\nAudit Structure\nYou will begin by listing ALL security headers that ARE present and properly configured.\n\nBe very clear and explicit about which headers are present and which are missing. For each header, clearly state whether it is present or missing, and if present, what its value is.\n\nThen, present your findings in three sections:\n- Header Security – Missing or misconfigured security headers\n- Cookie Security – Insecure cookie configurations\n- Content Security – CSP issues, mixed content, etc.\n\nFor each finding, provide:\n1. A clear description of the misconfiguration\n2. The security implications\n3. The recommended secure configuration with example code\n\nIf you find no issues in a particular section, explicitly state that no issues were found.\n\nUse proper formatting with code blocks for configuration examples. Only include issues that can be detected from client-side inspection.\nHere are the response headers: {{ $json.formattedHeaders }}\n\nPlease Respond like this\n\n### [any section heading that includes \"Headers]\n\n1. **[Header Title]**\n   - **Present?** Yes/No\n   - **Value:** `actual-header-value`\n","options":{},"promptType":"define"},"typeVersion":1.7},{"id":"3b43be75-c35c-44e4-8ecc-a29c48e3625c","name":"Merge Security Results","type":"n8n-nodes-base.merge","position":[860,580],"parameters":{},"typeVersion":3,"alwaysOutputData":true},{"id":"da134256-d7fa-4a3f-ba24-acc320a944a2","name":"Aggregate Audit Results","type":"n8n-nodes-base.aggregate","position":[1060,580],"parameters":{"options":{},"fieldsToAggregate":{"fieldToAggregate":[{"fieldToAggregate":"output"}]}},"typeVersion":1},{"id":"aef1da93-0b01-4a7f-9439-1f74c2af12d6","name":"Process Audit Results","type":"n8n-nodes-base.code","position":[1240,580],"parameters":{"jsCode":"// ✅ Updated extractSecurityHeaders and related logic remains unchanged\n\nfunction extractSecurityHeaders(rawHeaders = {}, configOutput = '') {\n  const securityHeaders = [\n    'Content-Security-Policy',\n    'Strict-Transport-Security',\n    'X-Content-Type-Options',\n    'X-Frame-Options',\n    'Referrer-Policy',\n    'Permissions-Policy',\n    'X-XSS-Protection',\n    'Cross-Origin-Embedder-Policy',\n    'Cross-Origin-Opener-Policy',\n    'X-Permitted-Cross-Domain-Policies'\n  ];\n\n  const headerStatus = {};\n  for (const header of securityHeaders) {\n    headerStatus[header] = { present: false, value: '' };\n  }\n\n  for (const header in rawHeaders) {\n    const norm = header.trim().toLowerCase();\n    for (const standard of securityHeaders) {\n      if (norm === standard.toLowerCase()) {\n        headerStatus[standard].present = true;\n        headerStatus[standard].value = rawHeaders[header];\n      }\n    }\n  }\n\n  const presentSection = configOutput.match(/(?:###|##|\\*\\*)[^\\n]*?\\bheaders?\\b[\\s\\S]*?(?=###|##|\\*\\*|$)/i);\n  if (presentSection) {\n    const section = presentSection[0];\n    for (const header of securityHeaders) {\n      const title = header.replace(/-/g, ' ').replace(/\\b\\w/g, c => c.toUpperCase());\n      const regex = new RegExp(`\\\\*\\\\*${title}\\\\*\\\\*[^\\\\n]*?\\\\*\\\\*Present\\\\?\\\\*\\\\*\\\\s*Yes[^\\\\n]*?\\\\*\\\\*Value:\\\\*\\\\*\\\\s*\\`([^\\\\\\`]+)\\``, 'is');\n      const match = section.match(regex);\n      if (match && match[1]) {\n        headerStatus[header].present = true;\n        headerStatus[header].value = match[1].trim();\n      }\n    }\n  }\n\n  return headerStatus;\n}\n\nfunction hasUnsafeInline(value) {\n  return value && value.includes('unsafe-inline');\n}\n\nfunction determineGrade(headerStatus) {\n  const critical = [\n    'Content-Security-Policy',\n    'Strict-Transport-Security',\n    'X-Content-Type-Options',\n    'X-Frame-Options'\n  ];\n  const important = ['Referrer-Policy', 'Permissions-Policy'];\n  const additional = [\n    'X-XSS-Protection',\n    'Cross-Origin-Embedder-Policy',\n    'Cross-Origin-Opener-Policy',\n    'X-Permitted-Cross-Domain-Policies'\n  ];\n\n  let criticalCount = 0;\n  let importantCount = 0;\n  let hasCSPIssue = false;\n\n  for (const h of critical) {\n    if (headerStatus[h]?.present) {\n      criticalCount++;\n      if (h === 'Content-Security-Policy' && hasUnsafeInline(headerStatus[h].value)) {\n        hasCSPIssue = true;\n      }\n    }\n  }\n\n  for (const h of important) {\n    if (headerStatus[h]?.present) importantCount++;\n  }\n\n  if (criticalCount === critical.length) {\n    if (importantCount === important.length) return hasCSPIssue ? 'A-' : 'A+';\n    if (importantCount >= 1) return hasCSPIssue ? 'B+' : 'A-';\n    return hasCSPIssue ? 'B' : 'B+';\n  } else if (criticalCount >= critical.length - 1) {\n    return importantCount >= 1 ? 'B' : 'C+';\n  } else if (criticalCount >= 2) {\n    return 'C';\n  } else if (criticalCount >= 1) {\n    return 'D';\n  } else {\n    return 'F';\n  }\n}\n\nfunction formatHeadersForDisplay(headerStatus) {\n  const present = Object.keys(headerStatus).filter(h => headerStatus[h].present);\n  return present.length > 0 ? present.join(', ') : 'No security headers detected';\n}\n\nfunction processSecurityHeaders(items) {\n  try {\n    const json = items[0].json || items[0];\n\n    // ⛏️ Try to grab from originalHeaders if available\n    const rawHeaders =\n      json?.originalHeaders ||\n      $('Extract Headers for Debug')?.first()?.json?.originalHeaders ||\n      json?.headers ||\n      {};\n\n    const configOutput = json.configOutput || json.output?.[0] || '';\n    const vulnOutput = json.vulnOutput || json.output?.[1] || '';\n\n    const headerStatus = extractSecurityHeaders(rawHeaders, configOutput);\n    const presentHeaders = formatHeadersForDisplay(headerStatus);\n    const grade = determineGrade(headerStatus);\n\n    const timestamp = new Date().toLocaleString('en-US', {\n      year: 'numeric',\n      month: 'long',\n      day: 'numeric',\n      hour: '2-digit',\n      minute: '2-digit'\n    });\n\n    const url =\n      json?.formValues?.url ||\n      json?.['Landing Page Url'] ||\n      $('Landing Page Url')?.first()?.json?.['Landing Page Url'] ||\n      json?.Landing_Page_Url ||\n      json?.landingPageUrl ||\n      json?.url ||\n      'https://example.com';\n\n    return [\n      {\n        json: {\n          ...json,\n          auditData: {\n            url,\n            timestamp,\n            grade,\n            criticalCount:\n              headerStatus['Content-Security-Policy'].present &&\n              hasUnsafeInline(headerStatus['Content-Security-Policy'].value)\n                ? 1\n                : 0,\n            warningCount: Object.keys(headerStatus).filter(\n              h =>\n                !headerStatus[h].present &&\n                !['Strict-Transport-Security', 'Content-Security-Policy'].includes(h)\n            ).length,\n            presentHeaders,\n            configOutput,\n            vulnOutput,\n            headerStatus,\n            originalHeaders: rawHeaders\n          }\n        }\n      }\n    ];\n  } catch (err) {\n    return [{ json: { ...items[0].json, error: err.message } }];\n  }\n}\n\nreturn processSecurityHeaders(items);\n"},"typeVersion":2},{"id":"ced29b26-474c-4d62-808a-3284103c9d60","name":"Send Security Report","type":"n8n-nodes-base.gmail","position":[1580,580],"webhookId":"2979e4dc-1689-447e-8cd4-eb907b4eedf4","parameters":{"sendTo":"=example@here.com","message":"={{ $json.emailHtml }}","options":{},"subject":"=Website Security Audit - {{ $json.auditData.url }}"},"credentials":{"gmailOAuth2":{"id":"9CEpbF4jIWb2OETv","name":"Gmail account"}},"typeVersion":2.1},{"id":"918c0fc4-2f02-4594-bfc9-e36035f2d802","name":"Sticky Note - Setup Instructions","type":"n8n-nodes-base.stickyNote","position":[-820,400],"parameters":{"width":500,"height":440,"content":"## Quick Setup Guide\n\n1. **Add OpenAI API Credentials**\n   - Go to Settings → Credentials → New → OpenAI API\n   - Enter your API key from platform.openai.com\n\n2. **Add Gmail Credentials**\n   - Go to Settings → Credentials → New → Gmail OAuth2 API\n   - Complete the OAuth setup process\n\n3. **Update Email Configuration**\n   - Open the 'Send Security Report' node\n   - Change the recipient email address from the default\n\n4. **Activate and Deploy Workflow**\n   - Click 'Active' toggle in the top right\n   - Copy the form URL to share with others or use yourself"},"typeVersion":1},{"id":"6e31b9b8-ae02-4da4-a75e-5d784b210c64","name":"Sticky Note - OpenAI Analysis","type":"n8n-nodes-base.stickyNote","position":[300,120],"parameters":{"color":3,"width":420,"height":240,"content":"## OpenAI Security Analysis\n\n- Add your OpenAI credentials (required)\n- Using GPT-4o models provides more detailed security analysis\n- Analyzes for XSS, information disclosure, CSRF, and more\n- Each agent scans different aspects of website security\n- Consider upgrading to GPT-4o (not mini) for production use"},"typeVersion":1},{"id":"590b1f1c-024d-4002-a8eb-d9dc81528f89","name":"Sticky Note - Email Configuration","type":"n8n-nodes-base.stickyNote","position":[1480,220],"parameters":{"color":3,"width":360,"height":200,"content":"## Send Security Report\n\n- Connects securely to Gmail for sending detailed reports\n- Report is sent as HTML formatted email\n- Subject line includes the scanned URL\n- Requires Gmail OAuth credentials to be set up"},"typeVersion":1},{"id":"dc6223f8-a98c-497a-97c9-af39e80e6d66","name":"Sticky Note - Audit Process","type":"n8n-nodes-base.stickyNote","position":[-200,780],"parameters":{"color":2,"width":420,"height":300,"content":"## Security Audit Process\n\n- This workflow performs two parallel security analyses\n- Top path: Checks headers, cookies, and security configurations\n- Bottom path: Analyzes HTML/JavaScript for client-side vulnerabilities\n- Results are merged and formatted into a comprehensive report\n- Analysis is non-invasive and only examines client-side content"},"typeVersion":1},{"id":"cbda16d4-f1f4-491c-b38c-43d7544e129b","name":"Sticky Note - How To Use","type":"n8n-nodes-base.stickyNote","position":[-240,240],"parameters":{"color":4,"width":400,"height":280,"content":"## How To Use This Workflow\n\n1. **Deploy the workflow** and activate it\n2. **Access the form** via the provided URL\n3. **Enter any website URL** to scan (must include http:// or https://)\n4. **Submit the form** to trigger the analysis\n5. **Check your email** for the detailed security report\n6. **Share the results** with your development team to implement fixes"},"typeVersion":1},{"id":"4859416f-4de3-43ea-9461-3ead8a38db6e","name":"Sticky Note - Report Formatting","type":"n8n-nodes-base.stickyNote","position":[1160,220],"parameters":{"color":5,"width":300,"height":280,"content":"## Report Formatting\n\n- Creates beautiful, professional HTML email report\n- Visual grade indicator (A-F) based on findings\n- Includes count of critical issues and warnings\n- Color-coded sections for easy readability\n- Mobile-friendly responsive design"},"typeVersion":1},{"id":"a02db4c7-2cad-41ff-b5ad-e1b19604a699","name":"Sticky Note - Results Processing","type":"n8n-nodes-base.stickyNote","position":[840,240],"parameters":{"width":300,"height":240,"content":"## Results Processing\n\n- Analyzes AI output to determine security grade\n- Counts critical issues and warnings\n- Extracts present security headers\n- Prepares data for the email report template\n- Generates timestamp for the report"},"typeVersion":1},{"id":"41b834c8-62f7-47e7-9d9d-e0e1244faecb","name":"Extract Headers for Debug","type":"n8n-nodes-base.code","position":[200,460],"parameters":{"jsCode":"// Format headers into a readable string\nlet formattedHeaders = '';\nif (items[0].json.headers) {\n  for (const key in items[0].json.headers) {\n    formattedHeaders += `${key}: ${items[0].json.headers[key]}\\n`;\n  }\n}\n\n// Return both the original data and the formatted headers\nreturn [{\n  json: {\n    ...items[0].json,\n    formattedHeaders: formattedHeaders,\n    originalHeaders: items[0].json.headers // Keep the original headers too\n  }\n}];"},"typeVersion":2},{"id":"0b76b396-fc96-41fc-a095-30971dd88271","name":"convert to HTML","type":"n8n-nodes-base.code","position":[1400,580],"parameters":{"jsCode":"// Create a direct HTML template with improved styling\nconst auditData = items[0].json.auditData;\n\nfunction formatConfigurationIssues() {\n  if (!auditData.configOutput || auditData.configOutput.trim() === '') {\n    return '<p>No specific configuration issues detected.</p>';\n  }\n\n  try {\n    const config = auditData.configOutput.trim();\n    let html = '';\n    const renderedKeys = new Set();\n\n    const renderBlock = (title, description, impact, recommendation) => `\n      <div style=\"border-left: 4px solid #3498DB; padding: 10px; margin-bottom: 15px;\">\n        <div style=\"font-weight: bold; color: #3498DB;\">${title}</div>\n        ${description ? `<div style=\"margin-top: 5px;\">${description}</div>` : ''}\n        ${impact ? `<div style=\"margin-top: 5px; font-style: italic; color: #7F8C8D;\">Impact: ${impact}</div>` : ''}\n        ${recommendation ? `<div style=\"margin-top: 5px;\"><strong>Recommendation:</strong></div>\n          <pre style=\"background-color: #f8f9fa; padding: 10px; border-radius: 5px; overflow-x: auto; font-family: monospace;\">${recommendation}</pre>` : ''}\n      </div>`;\n\n    const sections = config.split(/(?=^###\\s+)/gm).filter(Boolean);\n\n    for (const section of sections) {\n      const sectionTitleMatch = section.match(/^###\\s+(.*)/);\n      const sectionTitle = sectionTitleMatch?.[1]?.trim() || 'Unnamed Section';\n      const sectionKey = sectionTitle.toLowerCase();\n\n      // Skip \"no issues found\" sections\n      if (/no issues? (found|were found)/i.test(section)) continue;\n\n      const lines = section.split(/\\n+/).filter(line => line.trim() !== '');\n\n      let currentTitle = '';\n      let description = '';\n      let impact = '';\n      let recommendation = '';\n\n      for (let i = 0; i < lines.length; i++) {\n        const line = lines[i].trim();\n\n        // Start of a new numbered or bolded issue\n        const numberedTitle = line.match(/^\\d+\\.\\s+\\*\\*(.*?)\\*\\*/);\n        const bulletTitle = line.match(/^\\*\\*(.*?)\\*\\*/);\n\n        if (numberedTitle || (!currentTitle && bulletTitle)) {\n          // Flush last block\n          if (currentTitle && !renderedKeys.has(`${sectionKey}::${currentTitle.toLowerCase()}`)) {\n            html += renderBlock(currentTitle, description, impact, recommendation);\n            renderedKeys.add(`${sectionKey}::${currentTitle.toLowerCase()}`);\n          }\n\n          currentTitle = (numberedTitle || bulletTitle)[1].trim();\n          description = '';\n          impact = '';\n          recommendation = '';\n          continue;\n        }\n\n        const valueMatch = line.match(/- \\*\\*Value:\\*\\*\\s*`?(.*?)`?$/i);\n        const presentMatch = line.match(/- \\*\\*Present\\?\\*\\*.*?(Yes|No)/i);\n        const descMatch = line.match(/- \\*\\*Description:\\*\\*\\s*(.*)/i);\n        const impactMatch = line.match(/- \\*\\*(?:Impact|Security Implication|Potential Impact):\\*\\*\\s*(.*)/i);\n        const recMatch = line.match(/```(?:\\w*)?\\n([\\s\\S]*?)```/i);\n\n        if (descMatch) {\n          description = descMatch[1].trim();\n        } else if (valueMatch || presentMatch) {\n          const present = presentMatch?.[1]?.trim() || 'Unknown';\n          const value = valueMatch?.[1]?.trim() || '[Not provided]';\n          description = `This header is ${present.toLowerCase()}. Value: ${value}.`;\n        }\n\n        if (impactMatch) {\n          impact = impactMatch[1].trim();\n        }\n\n        if (recMatch) {\n          recommendation = recMatch[1].trim();\n        }\n      }\n\n      // Final block in section\n      if (currentTitle && !renderedKeys.has(`${sectionKey}::${currentTitle.toLowerCase()}`)) {\n        html += renderBlock(currentTitle, description, impact, recommendation);\n        renderedKeys.add(`${sectionKey}::${currentTitle.toLowerCase()}`);\n      }\n    }\n\n    return html || '<p>No configuration issues detected.</p>';\n  } catch (e) {\n    console.error('Error in formatConfigurationIssues:', e);\n    return `<p>Error processing configuration issues: ${e.message}</p>`;\n  }\n}\n\n\n\n// Create header badge HTML\nfunction createHeaderBadge(headerName, isWarning = false) {\n  const isPresent = auditData.headerStatus && \n                   auditData.headerStatus[headerName] && \n                   auditData.headerStatus[headerName].present;\n  \n  const color = isWarning && isPresent ? \"#F39C12\" : (isPresent ? \"#27AE60\" : \"#E74C3C\");\n  const icon = isPresent ? \"✓\" : \"✗\";\n  \n  return `<span style=\"display: inline-block; margin: 2px; padding: 4px 8px; background-color: ${color}; color: white; border-radius: 4px; font-size: 12px;\">${icon} ${headerName}</span>`;\n}\n\n// Format warnings section\nfunction formatWarningsSection() {\n  if (!auditData.warningCount || auditData.warningCount === 0 || !auditData.headerStatus) {\n    return '<p>No warnings detected.</p>';\n  }\n\n  const csp = Object.entries(auditData.headerStatus).find(([k]) => k.toLowerCase() === 'content-security-policy');\n  const hsts = Object.entries(auditData.headerStatus).find(([k]) => k.toLowerCase() === 'strict-transport-security');\n  const xss = Object.entries(auditData.headerStatus).find(([k]) => k.toLowerCase() === 'x-xss-protection');\n\n  let warnings = '';\n\n  if (csp && csp[1].value && csp[1].value.includes('unsafe-inline')) {\n    warnings += `\n      <div style=\"margin-top: 15px;\">\n        <div style=\"border-left: 4px solid #F39C12; padding: 10px;\">\n          <strong style=\"color: #F39C12;\">Content-Security-Policy: unsafe-inline</strong>\n          <p>The use of 'unsafe-inline' allows potentially malicious scripts to execute.</p>\n        </div>\n      </div>`;\n  }\n\n  if (hsts && hsts[1].value) {\n    const match = hsts[1].value.match(/max-age=(\\d+)/);\n    const age = match ? parseInt(match[1]) : 0;\n    if (age < 2592000) {\n      warnings += `\n        <div style=\"margin-top: 15px;\">\n          <div style=\"border-left: 4px solid #F39C12; padding: 10px;\">\n            <strong style=\"color: #F39C12;\">Strict-Transport-Security</strong>\n            <p>max-age is too low (${age}). Should be at least 2592000 (30 days).</p>\n          </div>\n        </div>`;\n    }\n  }\n\n  if (xss && !xss[1].present) {\n    warnings += `\n      <div style=\"margin-top: 15px;\">\n        <div style=\"border-left: 4px solid #F39C12; padding: 10px;\">\n          <strong style=\"color: #F39C12;\">Missing X-XSS-Protection</strong>\n          <p>This header enables the browser's XSS filter. Lack of it increases XSS risks.</p>\n        </div>\n      </div>`;\n  }\n\n  if (!warnings) {\n    warnings = `\n      <div style=\"margin-top: 15px;\">\n        <div style=\"border-left: 4px solid #F39C12; padding: 10px;\">\n          <strong style=\"color: #F39C12;\">${auditData.warningCount} warnings detected</strong>\n          <p>See the Configuration Issues section below for more info.</p>\n        </div>\n      </div>`;\n  }\n\n  return warnings;\n}\n\nfunction formatLongValue(value) {\n  if (!value || typeof value !== 'string') return '[empty]';\n\n  // Convert URLs into clickable links\n  value = value.replace(/(https?:\\/\\/[^\\s]+)/g, '<a href=\"$1\" style=\"color: #3498DB; text-decoration: none;\" target=\"_blank\">$1</a>');\n\n  // Add line breaks after commas or semicolons for readability\n  if (value.length > 100) {\n    value = value.replace(/([,;])\\s*/g, '$1<br>');\n  }\n\n  return value;\n}\n\nfunction formatDetailedRawHeaders() {\n  const allHeaders = [];\n  const seen = new Set();\n\n  const addHeader = (name, value) => {\n    const key = name.toLowerCase();\n    if (seen.has(key)) return;\n    seen.add(key);\n\n    const status = Object.entries(auditData.headerStatus || {}).find(\n      ([k]) => k.toLowerCase() === name.toLowerCase()\n    );\n    const present = status ? status[1].present : !!value;\n\n    allHeaders.push({\n      name: name.trim(),\n      present,\n      value: value || '[empty]'\n    });\n  };\n\n  Object.entries(auditData.originalHeaders || {}).forEach(([key, value]) => {\n    if (key) addHeader(key, value);\n  });\n\n  const securityHeaders = [\n    'content-security-policy',\n    'strict-transport-security',\n    'x-content-type-options',\n    'x-frame-options',\n    'referrer-policy',\n    'permissions-policy',\n    'x-xss-protection'\n  ];\n\n  const isWarningHeader = (name, value) => {\n    const lower = name.toLowerCase();\n    if (lower === 'strict-transport-security') {\n      const match = value.match(/max-age=(\\d+)/);\n      return match && parseInt(match[1]) < 2592000;\n    }\n    if (lower === 'content-security-policy') return value.includes(\"'unsafe-inline'\");\n    return false;\n  };\n\n  const tableRows = allHeaders.map(header => {\n    const isSecurity = securityHeaders.includes(header.name.toLowerCase());\n    const warning = isSecurity && isWarningHeader(header.name, header.value);\n    const missing = isSecurity && !header.present;\n\n    let bgColor = '#F8F9FA';\n    let textColor = '#333';\n\n    if (isSecurity) {\n      if (missing) {\n        bgColor = '#FFEBEE';\n        textColor = '#C62828';\n      } else if (warning) {\n        bgColor = '#FFF9C4';\n        textColor = '#F57F17';\n      } else {\n        bgColor = '#E8F5E9';\n        textColor = '#2E7D32';\n      }\n    }\n\n    return `\n      <tr style=\"background-color: ${bgColor}; color: ${textColor};\">\n        <td title=\"${isSecurity ? (missing ? 'Missing' : (warning ? 'Needs review' : 'Secure')) : 'Informational'}\" style=\"padding: 8px; font-weight: bold;\">${header.name}</td>\n        <td style=\"padding: 8px; text-align: center;\">${header.present ? 'present' : 'absent'}</td>\n        <td style=\"padding: 8px; word-break: break-word; font-family: monospace;\">${formatLongValue(header.value)}</td>\n      </tr>`;\n  }).join('');\n\n  return `\n    <table style=\"width: 100%; border-collapse: collapse; margin-top: 10px;\">\n      <thead>\n        <tr style=\"background-color: #E0E0E0;\">\n          <th style=\"padding: 10px;\">Header</th>\n          <th style=\"padding: 10px;\">Status</th>\n          <th style=\"padding: 10px;\">Value</th>\n        </tr>\n      </thead>\n      <tbody>\n        ${tableRows}\n      </tbody>\n    </table>`;\n}\n\n// Format additional information section\nfunction formatAdditionalInfo() {\n  const headers = [\n    {\n      name: 'access-control-allow-origin',\n      description: 'This is a very lax CORS policy. Such a policy should only be used on a public CDN.'\n    },\n    {\n      name: 'strict-transport-security',\n      description: 'HTTP Strict Transport Security is an excellent feature to support on your site and strengthens your implementation of TLS by getting the User Agent to enforce the use of HTTPS.'\n    },\n    {\n      name: 'content-security-policy',\n      description: 'Content Security Policy is an effective measure to protect your site from XSS attacks. By whitelisting sources of approved content, you can prevent the browser from loading malicious assets. Analyse this policy in more detail. You can sign up for a free account on Report URI to collect reports about problems on your site.'\n    },\n    {\n      name: 'permissions-policy',\n      description: 'Permissions Policy is a new header that allows a site to control which features and APIs can be used in the browser.'\n    },\n    {\n      name: 'referrer-policy',\n      description: 'Referrer Policy is a new header that allows a site to control how much information the browser includes with navigations away from a document and should be set by all sites.'\n    },\n    {\n      name: 'x-content-type-options',\n      description: 'X-Content-Type-Options stops a browser from trying to MIME-sniff the content type and forces it to stick with the declared content-type. The only valid value for this header is \"X-Content-Type-Options: nosniff\".'\n    },\n    {\n      name: 'x-frame-options',\n      description: 'X-Frame-Options tells the browser whether you want to allow your site to be framed or not. By preventing a browser from framing your site you can defend against attacks like clickjacking.'\n    },\n    {\n      name: 'report-to',\n      description: 'Report-To enables the Reporting API. This allows a website to collect reports from the browser about various errors that may occur. You can sign up for a free account on Report URI to collect these reports.'\n    },\n    {\n      name: 'nel',\n      description: 'Network Error Logging is a new header that instructs the browser to send reports during various network or application errors. You can sign up for a free account on Report URI to collect these reports.'\n    },\n    {\n      name: 'server',\n      description: 'Server value has been changed. Typically you will see values like \"Microsoft-IIS/8.0\" or \"nginx 1.7.2\".'\n    }\n  ];\n  \n  let rows = '';\n  \n  for (const header of headers) {\n    const isSecurityHeader = ['content-security-policy', 'strict-transport-security', 'x-content-type-options', 'x-frame-options', 'referrer-policy', 'permissions-policy'].includes(header.name);\n    const headerColor = isSecurityHeader ? '#27AE60' : '#3498DB';\n    \n    rows += `\n      <tr>\n        <td style=\"padding: 8px; border-bottom: 1px solid #eee; color: ${headerColor}; font-weight: bold;\">${header.name}</td>\n        <td style=\"padding: 8px; border-bottom: 1px solid #eee;\">${header.description}</td>\n      </tr>\n    `;\n  }\n  \n  return `\n    <table style=\"width: 100%; border-collapse: collapse; margin-top: 10px;\">\n      <tbody>\n        ${rows}\n      </tbody>\n    </table>\n  `;\n}\n\nfunction formatSecurityGrade() {\n  const gradeColors = {\n    'A+': '#27AE60',\n    'A': '#27AE60',\n    'A-': '#27AE60',\n    'B+': '#3498DB',\n    'B': '#3498DB',\n    'B-': '#3498DB',\n    'C+': '#F39C12',\n    'C': '#F39C12',\n    'C-': '#F39C12',\n    'D+': '#E74C3C',\n    'D': '#E74C3C',\n    'D-': '#E74C3C',\n    'F': '#E74C3C'\n  };\n  \n  return `<div class=\"grade\" style=\"font-size: 64px; font-weight: bold; width: 100px; height: 100px; line-height: 100px; text-align: center; background-color: ${gradeColors[auditData.grade] || '#E74C3C'}; color: white; border-radius: 5px; margin: 0 auto;\">${auditData.grade}</div>`;\n}\n\nfunction formatCriticalVulnerabilities() {\n  if (!auditData.vulnOutput || auditData.vulnOutput.trim() === '') {\n    return '<p>No vulnerabilities detected.</p>';\n  }\n\n  try {\n    const vuln = auditData.vulnOutput.trim();\n    let html = '';\n    const renderedTitles = new Set();\n\n    // Match sections like ## Category (e.g., ## Critical Vulnerabilities)\n    const categories = vuln.split(/(?=^##\\s+)/gm).filter(Boolean);\n\n    for (const categoryBlock of categories) {\n      const categoryMatch = categoryBlock.match(/^##\\s+(.*)/);\n      const categoryTitle = categoryMatch?.[1]?.trim() || 'Uncategorized';\n\n      // Find numbered items: 1. **Title**\n      const vulns = categoryBlock.split(/(?=^\\d+\\.\\s+\\*\\*)/gm).filter(Boolean);\n\n      for (const vulnBlock of vulns) {\n        const titleMatch = vulnBlock.match(/^\\d+\\.\\s+\\*\\*(.*?)\\*\\*/);\n        const title = titleMatch?.[1]?.trim() || 'Unnamed Vulnerability';\n        const key = `${categoryTitle}::${title}`.toLowerCase();\n        if (renderedTitles.has(key)) continue;\n\n        const descriptionMatch = vulnBlock.match(/\\*\\*Description\\*\\*:?\\s*([\\s\\S]*?)(?=\\n\\*\\*|\\n$)/i);\n        const impactMatch = vulnBlock.match(/\\*\\*(?:Impact|Potential Impact)\\*\\*:?\\s*([\\s\\S]*?)(?=\\n\\*\\*|\\n$)/i);\n        const recommendationMatch = vulnBlock.match(/\\*\\*(?:Recommendation|Mitigation|Fix)\\*\\*:?\\s*([\\s\\S]*?)(?=\\n\\*\\*|\\n$)/i);\n\n        const description = descriptionMatch?.[1]?.trim() || '';\n        const impact = impactMatch?.[1]?.trim() || '';\n        const recommendation = recommendationMatch?.[1]?.trim() || '';\n\n        if (description || impact || recommendation) {\n          html += `\n            <div style=\"border-left: 4px solid #E74C3C; padding: 10px; margin-bottom: 15px;\">\n              <div style=\"font-weight: bold; color: #E74C3C;\">${title}</div>\n              ${description ? `<div style=\"margin-top: 5px;\">${description}</div>` : ''}\n              ${impact ? `<div style=\"margin-top: 5px; font-style: italic; color: #7F8C8D;\">Impact: ${impact}</div>` : ''}\n              ${recommendation ? `<div style=\"margin-top: 5px;\"><strong>Recommendation:</strong> ${recommendation}</div>` : ''}\n            </div>`;\n          renderedTitles.add(key);\n        }\n      }\n    }\n\n    return html || '<p>No vulnerabilities parsed from output.</p>';\n  } catch (e) {\n    console.error('Error in formatCriticalVulnerabilities:', e);\n    return `<p>Error processing vulnerabilities: ${e.message}</p>`;\n  }\n}\n\n\n// Generate all security header badges\nfunction generateAllHeaderBadges() {\n  // Only include the necessary security headers\n  const securityHeaders = [\n    'Content-Security-Policy',\n    'Strict-Transport-Security',\n    'X-Content-Type-Options',\n    'X-Frame-Options',\n    'Referrer-Policy',\n    'Permissions-Policy'\n  ];\n  \n  let badges = '';\n  securityHeaders.forEach(header => {\n                      \n    const isWarning = header === 'Strict-Transport-Security' &&\n                  auditData.headerStatus?.[header]?.value &&\n                  parseInt(auditData.headerStatus[header].value.match(/max-age=(\\d+)/)?.[1] || 0) < 2592000;\n    \n    badges += createHeaderBadge(header, isWarning);\n  });\n  \n  return badges;\n}\n\n<!-- Modify the HTML to directly access auditData.originalHeaders or allHeaders -->\nconst html = `<!DOCTYPE html>\n<html>\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <title>Website Security Audit Report</title>\n    <style>\n        body { font-family: Arial, sans-serif; margin: 0; padding: 0; background-color: #f9f9f9; }\n        .container { max-width: 950px; margin: 0 auto; }\n        .header { background-color: #2c3e50; color: white; padding: 25px 20px; text-align: center; }\n        .header h1 { color: white; font-size: 28px; margin: 0; text-shadow: 1px 1px 2px rgba(0,0,0,0.5); }\n        .content { padding: 20px; }\n        .summary-box { background-color: #EBF5FB; padding: 15px; margin-bottom: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n        .warning-box { background-color: #FEF5E7; padding: 15px; margin-bottom: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n        .headers-box { background-color: #F5F7FA; padding: 15px; margin-bottom: 20px; border-radius: 5px; }\n        .findings-box { background-color: white; padding: 15px; margin-bottom: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n        .raw-headers-box { background-color: #F5F7FA; padding: 15px; margin-bottom: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n        .additional-info-box { background-color: #F5F7FA; padding: 15px; margin-bottom: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n        .details-table { width: 100%; border-collapse: collapse; }\n        .details-table th { text-align: left; padding: 8px; background-color: #f2f2f2; }\n        .details-table td { padding: 8px; border-bottom: 1px solid #eee; }\n        .header-badges { margin-top: 10px; }\n        h1, h2, h3 { color: #2c3e50; }\n        .critical-item { border-left: 4px solid #E74C3C; padding: 10px; margin-bottom: 15px; }\n        .critical-title { font-weight: bold; color: #E74C3C; }\n        .config-item { border-left: 4px solid #3498DB; padding: 10px; margin-bottom: 15px; }\n        .config-title { font-weight: bold; color: #3498DB; }\n        pre { background-color: #f8f9fa; padding: 10px; border-radius: 5px; overflow-x: auto; font-family: monospace; margin-top: 5px; }\n    </style>\n</head>\n<body>\n    <div class=\"container\">\n        <!-- Report Header -->\n        <div class=\"header\">\n            <h1 style=\"color: white; text-shadow: 1px 1px 2px rgba(0,0,0,0.5);\">Website Security Audit Report</h1>\n        </div>\n        \n        <div class=\"content\">\n            <!-- Security Report Summary -->\n            <div class=\"summary-box\">\n                <h2>Security Report Summary</h2>\n                <table style=\"width: 100%;\">\n                    <tr>\n                        <td style=\"width: 120px;\" valign=\"top\">\n                            ${formatSecurityGrade()}\n                        </td>\n                        <td valign=\"top\">\n                            <table style=\"width: 100%;\">\n                                <tr>\n                                    <td><strong>Site:</strong></td>\n                                    <td><a href=\"${auditData.url}\" style=\"color: #3498db;\">${auditData.url}</a></td>\n                                </tr>\n                                <tr>\n                                    <td><strong>Report Time:</strong></td>\n                                    <td>${auditData.timestamp}</td>\n                                </tr>\n                                <tr>\n                                    <td valign=\"top\"><strong>Headers:</strong></td>\n                                    <td>\n                                        <div class=\"header-badges\">\n                                            ${generateAllHeaderBadges()}\n                                        </div>\n                                    </td>\n                                </tr>\n                                <tr>\n                                    <td><strong>Critical Issues:</strong></td>\n                                    <td>${auditData.criticalCount || 0}</td>\n                                </tr>\n                                <tr>\n                                    <td><strong>Warnings:</strong></td>\n                                    <td>${auditData.warningCount || 0}</td>\n                                </tr>\n                            </table>\n                        </td>\n                    </tr>\n                </table>\n            </div>\n\n            <!-- Warnings Section -->\n            <div class=\"warning-box\">\n                <h2>Warnings</h2>\n                ${formatWarningsSection()}\n            </div>\n\n            <!-- Raw Headers Section -->\n            <div class=\"raw-headers-box\">\n                <h2>Raw Headers</h2>\n                ${formatDetailedRawHeaders()}\n            </div>\n\n            <!-- Security Findings -->\n            <div class=\"findings-box\">\n                <h2>Security Findings</h2>\n                \n                <!-- Vulnerabilities -->\n                <h3>Vulnerabilities</h3>\n                ${formatCriticalVulnerabilities()}\n                \n                <!-- Configuration Issues -->\n                <h3>Configuration Issues</h3>\n                ${formatConfigurationIssues()}\n            </div>\n            \n            <div class=\"additional-info-box\">\n              <h2>Additional Information</h2>\n              ${formatAdditionalInfo()}\n            </div>\n            \n            <!-- Implementation Guide -->\n            <div class=\"findings-box\">\n                <h2>Implementation Guide</h2>\n                <p>This report highlights security issues detected through client-side analysis. For a comprehensive security assessment, consider engaging a professional penetration tester.</p>\n                \n                <div style=\"background-color: #eafaf1; padding: 15px; margin-top: 15px; border-left: 4px solid #2ecc71; border-radius: 3px;\">\n                    <p><strong>To implement the fixes above:</strong></p>\n                    <ol style=\"padding-left: 20px; margin-top: 10px;\">\n                        <li>Work with your development team to address each issue in order of criticality</li>\n                        <li>Retest after implementing each fix</li>\n                        <li>Consider implementing a web application firewall for additional protection</li>\n                    </ol>\n                </div>\n            </div>\n            \n            <!-- Footer -->\n            <div style=\"text-align: center; padding: 20px; font-size: 12px; color: #777;\">\n                <p>This report was automatically generated and represents an automated assessment of publicly accessible aspects of your website. For a more comprehensive security assessment, consider engaging with a professional security consultant.</p>\n                <p>&copy; 2025 Website Security Scanner | Generated on ${auditData.timestamp}</p>\n            </div>\n        </div>\n    </div>\n</body>\n</html>`;\n\nreturn [{\n  json: {\n    ...items[0].json,\n    emailHtml: html\n  }\n}];"},"typeVersion":2}],"pinData":{},"connections":{"Scrape Website":{"main":[[{"node":"Security Vulnerabilities Audit","type":"main","index":0},{"node":"Extract Headers for Debug","type":"main","index":0}]]},"convert to HTML":{"main":[[{"node":"Send Security Report","type":"main","index":0}]]},"Landing Page Url":{"main":[[{"node":"Scrape Website","type":"main","index":0}]]},"Process Audit Results":{"main":[[{"node":"convert to HTML","type":"main","index":0}]]},"Merge Security Results":{"main":[[{"node":"Aggregate Audit Results","type":"main","index":0}]]},"Aggregate Audit Results":{"main":[[{"node":"Process Audit Results","type":"main","index":0}]]},"OpenAI Content Analysis":{"ai_languageModel":[[{"node":"Security Vulnerabilities Audit","type":"ai_languageModel","index":0}]]},"OpenAI Headers Analysis":{"ai_languageModel":[[{"node":"Security Configuration Audit","type":"ai_languageModel","index":0}]]},"Extract Headers for Debug":{"main":[[{"node":"Security Configuration Audit","type":"main","index":0}]]},"Security Configuration Audit":{"main":[[{"node":"Merge Security Results","type":"main","index":0}]]},"Security Vulnerabilities Audit":{"main":[[{"node":"Merge Security Results","type":"main","index":1}]]}}}


name: Automate Blog Content Creation with GPT-4, Perplexity & WordPress
author_name: Dr. Firas
author_username: drfiras
categories: []
created_at: 2025-03-26T21:04:55.087Z
updated_at: 2025-03-26T21:04:55.087Z
url: https://n8n.io/workflows/3336
scraped_at: 2025-06-19 22:49:32
description:
  Who Is This For

  This workflow is ideal for content creators, solo founders, marketers, and AI enthusiasts who want to automate the full process of blog content creation.  
  It is especially useful for professionals in tech, AI, and automation who publish frequently and need SEO-ready content fast.

  What Problem Does This Workflow Solve

  Creating SEO-optimized blog content is time-consuming and requires consistency.  
  Manually researching trending topics slows down the content pipeline.  
  Formatting, publishing, and promoting across multiple platforms takes effort.  
  This workflow automates the entire process from research to publication.

  What This Workflow Does

  Research: Uses Perplexity AI to gather up-to-date content ideas via form input.  
  Content Generation: GPT-4 creates a short, SEO-optimized article (max 20 lines) with H1, H2 structure and meta-description.  
  Publishing: Automatically posts the content to WordPress.  
  Email Notification: Sends the article title and URL via Gmail.  
  Slack Notification: Notifies a specified Slack channel when the article is live.  
  Database Logging: Saves the article details to a Notion database.

  Setup Guide

  Prerequisites

  WordPress account with API access  
  OpenAI API Key  
  Perplexity API Key  
  Slack Bot Token  
  Notion integration (Database ID)  
  Gmail API credentials (optional)  
  Community Node Required: This workflow uses n8n-nodes-mcp, which only works on self-hosted instances of n8n.  
    &gt; To install: Go to Settings &gt; Community Nodes &gt; Install n8n-nodes-mcp

  Steps

  Import the workflow into your n8n instance  
  Install the required community node (n8n-nodes-mcp)  
  Set up API credentials for OpenAI, Perplexity, WordPress, Slack, Gmail, and Notion  
  Customize the form trigger with your preferred prompt  
  Run a test using a sample topic

  How to Customize This Workflow

  Modify the research prompt to match your niche or industry  
  Adjust GPT-4 settings for tone, structure, or content length  
  Customize Notion fields (e.g., add tags, categories, or labels)  
  Add logic for generating or assigning featured images automatically

nodes_used:
  ["n8n-nodes-base.httpRequest","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi"]

workflow_json:
  {"id":"L1UcBZ9UJvN9gnSb","meta":{"instanceId":"a2b23892dd6989fda7c1209b381f5850373a7d2b85609624d7c2b7a092671d44","templateCredsSetupCompleted":true},"name":"💥🛠️Automate Blog Content Creation with GPT-4, Perplexity & WordPress","tags":[],"nodes":[{"id":"b86a4b08-6fb6-4ebc-8ddb-f1cd0e4b1492","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[0,0],"parameters":{"color":4,"width":460,"height":300,"content":"## Perplexity Section\n🌐 Calls Perplexity API to get fresh research based on a form input.\n\n\n"},"typeVersion":1},{"id":"16509f9d-ce54-4dab-b3ff-24760b0bde09","name":"Perplexity Research","type":"n8n-nodes-base.httpRequest","position":[80,100],"parameters":{"url":"https://api.perplexity.ai/chat/completions","method":"POST","options":{},"jsonBody":"={\n  \"model\": \"sonar-pro\",\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"Act as a professional news researcher who is capable of finding detailed summaries about a news topic from highly reputable sources.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \" Research the following topic and return everything you can find about: '{{ $json['Topic or Question'] }}'.\"\n    }\n  ]\n}\n","sendBody":true,"specifyBody":"json","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"DB99xYLrmwZl7Sqf","name":"Header Auth account"}},"typeVersion":4.2},{"id":"500b2464-88b1-44f5-bcc4-12c0acdc5773","name":"When chat message received","type":"@n8n/n8n-nodes-langchain.chatTrigger","position":[560,0],"webhookId":"b132ff74-2807-4cbf-b5b7-a62a207161d3","parameters":{"options":{}},"typeVersion":1.1},{"id":"aec9523b-245a-48ff-a860-3239b869f676","name":"Slack-List","type":"n8n-nodes-mcp.mcpClientTool","position":[1500,400],"parameters":{},"credentials":{"mcpClientApi":{"id":"mC6b1h1p0lFikSzU","name":"slack"}},"typeVersion":1},{"id":"1ecdcfed-c5d4-4ddc-aeb1-e760d295e5bc","name":"Copywriting AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[1020,100],"parameters":{"text":"=You are an expert in SEO content writing.\n\nYour mission is to create, publish, and notify about a search engine optimized article for a blog focused on artificial intelligence. Follow the steps below: {{ $('Format Research Output').item.json.research }}\n\n1. **Write an SEO-optimized article with a maximum of 20 lines** based on the provided information:\n   - Structure the article with a catchy **H1 title**, one or two **H2 subtitles**, and a professional yet accessible tone.\n   - Extract and include relevant keywords from the data.\n   - Optimize for readability: short sentences, clear paragraphs, and a CTA if relevant.\n   - Do not exceed 20 lines of content.\n\n2. **Publish the article on WordPress**, including:\n   - The **title** as the article's headline\n   - The **SEO content** as the body\n\n3. **Send an email** to my address : {{ $json.emailAddress }} containing:\n   - The article's title\n   - The **URL** of the published article on WordPress\n\n4. **Retrieve the list of available Slack tools first** using “Slack Tools”.\n   - Then, send a notification on Slack that the article has been published, including:\n     - The article title\n     - The article link\n     - Slack channel ID: {{ $json.slackChannelId }}\n\n5. **Retrieve the list of available Notion tools first** using “Notion Tools”.\n   Then, **add a new entry to my Notion database** (ID: {{ $json.notionDatabaseId }}) with the following fields:\n   - The 'Name' column is of type 'title'  → {{ $('Start with Research Query Submission').item.json['Topic or Question'] }}\n   The 'Subject' column is of type 'rich_text' → [the article's headline]\n   - The 'Content'column is of type 'rich_text' → [The SEO content]\n   - The 'URL' column is of type 'URL': → [The article link]\n   - The 'Status' column is of type 'select' → Select: `publish`\n\nImportant: Ensure that each step is successfully completed **before proceeding to the next**.\n","options":{},"promptType":"define"},"typeVersion":1.7},{"id":"aaab95dd-7fd2-411e-ba05-fa84568c0d56","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[480,-180],"parameters":{"width":1300,"height":820,"content":"## My Copywriting AI Agent\n✍️ Transforms live research into SEO-optimized blog articles using GPT-4, then automatically publishes to WordPress, sends notifications via Gmail & Slack, and logs everything to Notion. This is your full-stack content assistant — from prompt to post, hands-free.\n**mcp-notion-server** : [Guide](https://github.com/suekou/mcp-notion-server)\n**mcp-slack-server** : [Guide](https://github.com/modelcontextprotocol/servers/tree/main/src/slack)"},"typeVersion":1},{"id":"d3cbf58c-7c14-4695-8331-1750daf21d0d","name":"Format Research Output","type":"n8n-nodes-base.set","position":[280,100],"parameters":{"options":{},"assignments":{"assignments":[{"id":"23b8e8c4-9191-415a-9661-1b60d413528a","name":"research","type":"string","value":"={{ $json.choices[0].message.content.replaceAll(\"[1]\", \" - source: \" +$json.citations[0]).replaceAll(\"[2]\",\" - source:\" +$json.citations[1]).replaceAll(\"[3]\",\" - source: \" +$json.citations[2]).replaceAll(\"[4]\",\" - source: \"+$json.citations[3]).replaceAll(\"[5]\",\" - source: \"+$json.citations[4]).replaceAll(\"[6]\",\" - source: \"+$json.citations[5]).replaceAll(\"[7]\",\" - source: \"+$json.citations[6]).replaceAll(\"[8]\",\" - source: \"+$json.citations[7]).replaceAll(\"[9]\",\" - source: \"+$json.citations[8]).replaceAll(\"[10]\",\" - source: \"+$json.citations[9]) }}"}]}},"typeVersion":3.4},{"id":"cd073bb3-3b6a-4910-9de4-bef66fc00a1f","name":"Publish Article to WordPress","type":"n8n-nodes-base.wordpressTool","position":[840,400],"parameters":{"title":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Title', ``, 'string') }}","additionalFields":{"status":"publish","content":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Content', ``, 'string') }}"}},"credentials":{"wordpressApi":{"id":"KIuXvzjOEnOsHKQE","name":"Wordpress account"}},"typeVersion":1},{"id":"6940575a-d504-4276-8964-c41f26418f3c","name":"Send Email Notification","type":"n8n-nodes-base.gmailTool","position":[1360,400],"webhookId":"b68c6af8-46e6-4ed9-ae72-445e9cb7ab88","parameters":{"sendTo":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('To', ``, 'string') }}","message":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Message', ``, 'string') }}","options":{},"subject":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Subject', ``, 'string') }}"},"credentials":{"gmailOAuth2":{"id":"rKxQHWZ2F5XLJmwF","name":"Gmail account"}},"typeVersion":2.1},{"id":"da3c994c-60d5-41ef-9cf9-52daa77dc980","name":"Notify Slack Channel","type":"n8n-nodes-mcp.mcpClientTool","position":[1640,400],"parameters":{"toolName":"={{ $fromAI(\"tool\", \"the tool selected\")  }}","operation":"executeTool","toolParameters":"={{ $fromAI('Tool_Parameters', ``, 'json') }}"},"credentials":{"mcpClientApi":{"id":"mC6b1h1p0lFikSzU","name":"slack"}},"typeVersion":1},{"id":"9d36b649-f5e6-442c-bcab-53f0ca0dc2c2","name":"Generate SEO Blog Content (GPT-4o)","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[600,400],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"6h3DfVhNPw9I25nO","name":"OpenAi account"}},"typeVersion":1.2},{"id":"7a034005-68a3-40fa-bb94-cfdfab717cfc","name":"Start with Research Query Submission","type":"n8n-nodes-base.formTrigger","position":[-180,100],"webhookId":"a29cbcd3-9d11-4f7c-9aad-14681c356c53","parameters":{"options":{},"formTitle":"AutoBlog Creator","formFields":{"values":[{"fieldType":"textarea","fieldLabel":"Topic or Question","placeholder":"=How is GPT-4 transforming content creation in 2025?","requiredField":true}]},"formDescription":"From research to article — no writing required"},"typeVersion":2.2},{"id":"8cbad4aa-1802-4275-bbc4-c4d17673cd23","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[0,-180],"parameters":{"color":3,"width":460,"height":140,"content":"## Intro Sticky \n🔁 **This workflow automates the full cycle of SEO blog content creation** — from live topic research using Perplexity to blog publishing on WordPress, Slack/Gmail notifications, and Notion logging."},"typeVersion":1},{"id":"93e258e4-baa2-4af2-ba12-0f1727150e19","name":"Edit Workflow Variables","type":"n8n-nodes-base.set","position":[120,460],"parameters":{"options":{},"assignments":{"assignments":[{"id":"c06b2d24-1fd7-40f0-aee5-b5d6553e289e","name":"emailAddress","type":"string","value":""},{"id":"451aad67-5190-4eab-a982-56092734bb07","name":"slackChannelId","type":"string","value":""},{"id":"8a294900-f367-47a2-b260-344b133dc2ff","name":"notionDatabaseId","type":"string","value":""}]}},"typeVersion":3.4,"alwaysOutputData":true},{"id":"88cb2c49-be54-4df9-81ff-d709bde839e1","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[0,340],"parameters":{"color":6,"width":460,"height":300,"content":"## Workflow Configuration Panel\n🛠️ **Set your variables here** (email, Slack, Notion, OpenAI model)"},"typeVersion":1},{"id":"5075e00d-f1e9-4db2-85c1-d4d851f57abf","name":"Notion-List","type":"n8n-nodes-mcp.mcpClientTool","position":[1000,400],"parameters":{},"credentials":{"mcpClientApi":{"id":"QQbMEB7i2XAAWTSc","name":"Notion"}},"typeVersion":1},{"id":"edf2d95b-b04d-40f9-9b8d-b53dd5912bab","name":"Insert Article in Notion","type":"n8n-nodes-mcp.mcpClientTool","position":[1180,400],"parameters":{"toolName":"={{ $fromAI(\"tool\", \"the tool selected\")  }}","operation":"executeTool","toolParameters":"={{ $fromAI('tool_parameters', ``, 'json') }}"},"credentials":{"mcpClientApi":{"id":"QQbMEB7i2XAAWTSc","name":"Notion"}},"typeVersion":1}],"active":true,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"553f26d7-2dcf-4900-871e-b3aa25a68ffa","connections":{"Slack-List":{"ai_tool":[[{"node":"Copywriting AI Agent","type":"ai_tool","index":0}]]},"Notion-List":{"ai_tool":[[{"node":"Copywriting AI Agent","type":"ai_tool","index":0}]]},"Perplexity Research":{"main":[[{"node":"Format Research Output","type":"main","index":0}]]},"Notify Slack Channel":{"ai_tool":[[{"node":"Copywriting AI Agent","type":"ai_tool","index":0}]]},"Format Research Output":{"main":[[{"node":"Edit Workflow Variables","type":"main","index":0}]]},"Edit Workflow Variables":{"main":[[{"node":"Copywriting AI Agent","type":"main","index":0}]]},"Send Email Notification":{"ai_tool":[[{"node":"Copywriting AI Agent","type":"ai_tool","index":0}]]},"Insert Article in Notion":{"ai_tool":[[{"node":"Copywriting AI Agent","type":"ai_tool","index":0}]]},"When chat message received":{"main":[[{"node":"Copywriting AI Agent","type":"main","index":0}]]},"Publish Article to WordPress":{"ai_tool":[[{"node":"Copywriting AI Agent","type":"ai_tool","index":0}]]},"Generate SEO Blog Content (GPT-4o)":{"ai_languageModel":[[{"node":"Copywriting AI Agent","type":"ai_languageModel","index":0}]]},"Start with Research Query Submission":{"main":[[{"node":"Perplexity Research","type":"main","index":0}]]}}}


name: Automate Blog Content Creation with Notion MCP, DeepSeek AI, and WordPress
author_name: Dr. Firas
author_username: drfiras
nodes_used: ["@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatDeepSeek"]
categories: []
created_at: 2025-03-29T03:27:21.509Z
updated_at: 2025-03-29T03:27:21.509Z
url: https://n8n.io/workflows/3348
scraped_at: 2025-06-19 22:50:18
description:
  Who Is This For
  This workflow is ideal for content creators, bloggers, marketers, and professionals seeking to automate the creation and publication of SEO-optimized articles. It's particularly beneficial for those utilizing Notion for content management and WordPress for publishing.​

  What Problem Does This Workflow Solve
  Manually creating SEO-friendly articles is time-consuming and requires consistent effort. This workflow streamlines the entire process—from detecting updates in Notion to publishing on WordPress—by leveraging AI for content generation, thereby reducing the time and effort involved.​

  What This Workflow Does
  Monitor Notion Updates: Detects changes in a specified Notion database.​
  AI Content Generation: Utilizes an AI model to produce an SEO-optimized article based on Notion data.​
  Publish to WordPress: Automatically posts the generated article to a WordPress site.​
  Email Notification: Sends an email containing the article's title and URL.​

  Update Notion Database: Updates the corresponding entry in the Notion database with the article details.​

  Setup Guide
  Prerequisites
  WordPress account with API access.​
  API key for the AI model used.​
  Notion integration with the relevant database ID.​
  Credentials for the email service used (e.g., Gmail).​

  Community Node Requirement: This workflow utilizes the n8n-nodes-mcp community node, which is only compatible with self-hosted instances of n8n. For more information on installing and managing community nodes, refer to the n8n documentation.​
  n8n Docs

  Steps
  Import the workflow into your self-hosted n8n instance.​
  Install the required community node (n8n-nodes-mcp).​
  Configure API credentials for WordPress, the AI service, Notion, and the email service.​
  Define necessary variables, such as the notification email address and Notion database IDs.​
  Activate the workflow to automate the process.​

  How to Customize This Workflow
  AI Prompt: Adjust the prompt used for content generation to align with your preferred tone and style.​
  Article Structure: Modify the structure of the generated article by tweaking settings in the content generation node.​
  Notifications: Customize the content and recipients of the emails sent post-publication.​
  Notion Updates: Tailor the fields updated in Notion to suit your specific requirements.

workflow_json:
  {"id":"7eyNPahKcCuqK39V","meta":{"instanceId":"a2b23892dd6989fda7c1209b381f5850373a7d2b85609624d7c2b7a092671d44","templateCredsSetupCompleted":true},"name":"DeepSeek v3.1","tags":[{"id":"ZGwSiT2o3NGleZvi","name":"DeepSeek","createdAt":"2025-03-28T00:29:11.856Z","updatedAt":"2025-03-28T00:29:11.856Z"}],"nodes":[{"id":"5ccc1b78-0795-4653-8438-c9a65781e516","name":"Watch Notion Updates","type":"n8n-nodes-base.notionTrigger","position":[-620,-100],"parameters":{"event":"pagedUpdatedInDatabase","pollTimes":{"item":[{"mode":"everyHour"}]},"databaseId":{"__rl":true,"mode":"id","value":"1c33d655-0fd9-8057-ac1a-eabf12d12f6b","__regex":"^([0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12})"}},"credentials":{"notionApi":{"id":"5rz9xchmiSCmcoOx","name":"Notion account"}},"typeVersion":1},{"id":"f6bcd3cd-6bf9-42d7-a54a-31e945d5730d","name":"AI Task Planner","type":"@n8n/n8n-nodes-langchain.agent","position":[320,-100],"parameters":{"text":"=You are an expert in SEO content writing.\nYour mission is to create, publish, and notify about a search engine-optimized article for a blog.\nHere are the keywords related to my topic:  {{ $('Watch Notion Updates').item.json.Name }}\n\nFollow the steps below:\n\n1. **Write an SEO-optimized article with a maximum of 20 lines** based on the provided information:\n   - Structure the article with a catchy **H1 title**, one or two **H2 subtitles**, and a professional yet accessible tone.\n   - Extract and include relevant keywords from the data.\n   - Optimize for readability: short sentences, clear paragraphs, and a CTA if relevant.\n   - Do not exceed 20 lines of content.\n\n2. **Publish the article on WordPress**, including:\n   - The **title** as the article's headline\n   - The **SEO content** as the body\n\n3. **Send an email** to my address : {{ $json.emailAddress }} containing:\n   - The article's title\n   - The **URL** of the published article on WordPress\n\n4. **Retrieve the list of available Notion tools first** using “Notion Tools”.\n   Then, **add a update the entry to my Notion database** (ID database: {{ $json.notionDatabaseId }}) ID items : {{ $json.notionItemId }}\nwith the following fields:\n   - The 'Name' column is of type 'title'  → {{ $('Watch Notion Updates').item.json.Name }}\n   The 'Subject' column is of type 'rich_text' → [the article's headline]\n   - The 'Content'column is of type 'rich_text' → [The SEO content]\n   - The 'URL' column is of type 'URL': → [The article link]\n   - The 'Status' column is of type 'select' → Select: `publish`\n\nImportant: Ensure that each step is successfully completed **before proceeding to the next**.","options":{},"promptType":"define"},"typeVersion":1.7},{"id":"1627a1ae-424e-4124-ac09-bd0f7bc92d2b","name":"Send Email","type":"n8n-nodes-base.gmailTool","position":[380,160],"webhookId":"f87279e8-34e4-4fd1-81d3-677707e215de","parameters":{"sendTo":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('To', ``, 'string') }}","message":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Message', ``, 'string') }}","options":{},"subject":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Subject', ``, 'string') }}"},"credentials":{"gmailOAuth2":{"id":"rKxQHWZ2F5XLJmwF","name":"Gmail account"}},"typeVersion":2.1},{"id":"c9c6f4f5-59ff-4c58-8fbd-f7cc0bd3eb2d","name":"Publish Blog Post","type":"n8n-nodes-base.wordpressTool","position":[500,160],"parameters":{"title":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Title', ``, 'string') }}","additionalFields":{"status":"draft","content":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Content', ``, 'string') }}"}},"credentials":{"wordpressApi":{"id":"KIuXvzjOEnOsHKQE","name":"Wordpress account"}},"typeVersion":1},{"id":"0064198f-cfe0-424b-9a75-afbdd8a67c14","name":"Notion List Available Tools","type":"n8n-nodes-mcp.mcpClientTool","position":[660,160],"parameters":{},"credentials":{"mcpClientApi":{"id":"QQbMEB7i2XAAWTSc","name":"Notion"}},"typeVersion":1},{"id":"fac061a7-0e91-4944-82f6-463db3e418ce","name":"Notion Run a Tool","type":"n8n-nodes-mcp.mcpClientTool","position":[820,160],"parameters":{"toolName":"={{ $fromAI(\"tool\", \"the tool selected\")  }}","operation":"executeTool","toolParameters":"={{ $fromAI('tool_parameters', ``, 'json') }}"},"credentials":{"mcpClientApi":{"id":"QQbMEB7i2XAAWTSc","name":"Notion"}},"typeVersion":1},{"id":"378f291a-bea7-47b3-a629-07fb8d3f9110","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-60,-220],"parameters":{"width":1100,"height":580,"content":"## Smart Content Automation Workflow\nAutomatically reacts to Notion updates, uses AI to process data, and triggers actions like sending emails or publishing blog posts.\n**Openrouter** : [API](https://openrouter.ai/settings/keys)"},"typeVersion":1},{"id":"5a8d00c1-752d-4573-ace8-e578b58892d4","name":"Edit Workflow Variables","type":"n8n-nodes-base.set","position":[-300,-100],"parameters":{"options":{},"assignments":{"assignments":[{"id":"c06b2d24-1fd7-40f0-aee5-b5d6553e289e","name":"emailAddress","type":"string","value":""},{"id":"8a294900-f367-47a2-b260-344b133dc2ff","name":"notionDatabaseId","type":"string","value":""},{"id":"a34469ad-5229-4c4d-bc5d-71c88686bd37","name":"notionItemId","type":"string","value":"={{ $json.id }}"}]}},"typeVersion":3.4,"alwaysOutputData":true},{"id":"3e76c55d-9052-4568-9e21-29e8fd305369","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-440,-220],"parameters":{"color":6,"width":360,"height":300,"content":"## Workflow Configuration Panel\n🛠️ **Set your variables here** (email, Slack, Notion, OpenAI model)"},"typeVersion":1},{"id":"27f461de-609a-4743-829c-74705191e692","name":"DeepSeek Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatDeepSeek","position":[100,160],"parameters":{"options":{}},"credentials":{"deepSeekApi":{"id":"N4JPoebNdVQUNxXH","name":"DeepSeek account"}},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"1eae918e-03f8-49d8-9dea-cf0e441e679d","connections":{"Send Email":{"ai_tool":[[{"node":"AI Task Planner","type":"ai_tool","index":0}]]},"Notion Run a Tool":{"ai_tool":[[{"node":"AI Task Planner","type":"ai_tool","index":0}]]},"Publish Blog Post":{"ai_tool":[[{"node":"AI Task Planner","type":"ai_tool","index":0}]]},"DeepSeek Chat Model":{"ai_languageModel":[[{"node":"AI Task Planner","type":"ai_languageModel","index":0}]]},"Watch Notion Updates":{"main":[[{"node":"Edit Workflow Variables","type":"main","index":0}]]},"Edit Workflow Variables":{"main":[[{"node":"AI Task Planner","type":"main","index":0}]]},"Notion List Available Tools":{"ai_tool":[[{"node":"AI Task Planner","type":"ai_tool","index":0}]]}}}


name: Telegram AI Bot-to-Human Handoff for Sales Calls
author_name: Jimleuk
author_username: jimleuk
categories: []
created_at: 2025-03-29T15:23:05.743Z
updated_at: 2025-03-29T15:23:05.743Z
url: https://n8n.io/workflows/3350
scraped_at: 2025-06-19 22:50:13
description:
  This n8n template demonstrates an approach to perform bot-to-human handoff using Human-in-the-loop functionality as a switch.

  In this experiment, we play with the idea of states we want our agent to be in which controls it's interacton with the user.
  First state** - the agent is onboarding the user by collecting their details for a sales inquiry. After which, they are handed-off / transferred to a human to continue the call.
  Second state** - the agent is essentially "deactivated" as further messages to the bot will not reach it. Instead, a canned response is given to the user. The human agent must "reactivate" the bot by completing the human-in-the-loop form and give a summary of their conversation with the user.
  Third state** - the agent is "reactivated" with context of the human-to-user conversation and is set to provide after sales assistance. An tool is made available to the agent to again delegate back to the human agent when requested.

  How it works
  This template uses telegram to handle the interaction between the user and the agent.
  Each user message is checked for a session state to ensure it is guided to the right stage of the conversation. For this, we can use Redis as a simple key-value store.
  When no state is set, the user is directed through an onboarding step to attain their details. Once complete, the agent will "transfer" the user to a human agent - technically, all this involves is an update to the session state and a message to another chat forwarding the user's details.
  During this "human" state, the agent cannot reply to the user and must wait until the human "transfers" the conversation back. The human can do this by replying to "human-in-the-loop" message with a summary of their conversation with the user. This session state now changes to "bot" and the context is implanted in the agent's memory so that the agent can respond to future questions.
  At this stage of the conversation, the agent is now expected to handle and help the user with after-sales questions. The user can at anytime request transfer back to the human agent, repeating the previous steps as necessary.

  How to use
  Plan your user journey! Here is a very basic example of a sales inquiry with at most 3 states. More thought should be developed when many more states are involved.
  You may want to better log and manage session states so no user is left in limbo. Try connecting the user and sessions to your CRM.
  Note, the Onboarding agent and After-Sales agent have separate chat memories. When adding more agents, it is recommend to continue having separate chat memories to help focus between states.

  Requirements
  Telegram for chatbot & interface
  Redis for session store and chat memory
  OpenAI for AI agent

  Customising this workflow
  Not using Telegram? This template works with Whatsapp and other services with equivalent functionality.

nodes_used:
  ["n8n-nodes-base.redis","n8n-nodes-base.telegram","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryRedisChat","@n8n/n8n-nodes-langchain.toolWorkflow","@n8n/n8n-nodes-langchain.memoryManager","@n8n/n8n-nodes-langchain.informationExtractor"]

workflow_json:
  {"meta":{"instanceId":"408f9fb9940c3cb18ffdef0e0150fe342d6e655c3a9fac21f0f644e8bedabcd9","templateCredsSetupCompleted":true},"nodes":[{"id":"5d6a5a45-8aa8-4c34-aa10-5dd85f05de9d","name":"Human Handoff using Send and Wait","type":"n8n-nodes-base.telegram","position":[1580,1040],"webhookId":"d2bbc82f-0509-470a-af4d-9d92cfed4d5f","parameters":{"chatId":"=<human chat id>","message":"=chatId: {{ $('Handoff Subworkflow').first().json.chatId }}\nsessionId: {{ $('Handoff Subworkflow').first().json.sessionId }}\nuser: {{ $('Handoff Subworkflow').first().json.username }} ({{ $('Handoff Subworkflow').item.json.userId }})\n\nSummary:\n{{ $('Handoff Subworkflow').item.json.summary }}\n\n---\nThis user has now been handed off to a human.\nClick the button to return user to bot.","options":{},"operation":"sendAndWait","responseType":"freeText"},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2},{"id":"5d2f73ff-b233-4456-b34d-d5a5454dabda","name":"Set Interaction to Bot","type":"n8n-nodes-base.redis","position":[1780,1040],"parameters":{"key":"=handoff_{{ $('Handoff Subworkflow').first().json.sessionId }}_state","value":"bot","keyType":"string","operation":"set"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1},{"id":"f799e213-f3ed-4479-aade-7a7c38eb5792","name":"Set Interaction to Human","type":"n8n-nodes-base.redis","position":[1380,1040],"parameters":{"key":"=handoff_{{ $json.sessionId }}_state","value":"=human","keyType":"string","operation":"set"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1},{"id":"059c9b8c-ba50-4bdd-8969-6f5f35bba304","name":"Get Interaction State","type":"n8n-nodes-base.redis","position":[-800,820],"parameters":{"key":"=handoff_{{ $json.message.chat.id }}_state","options":{},"operation":"get","propertyName":"data"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1},{"id":"8afd48ff-478d-4092-ac88-fb2e435ded00","name":"Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-280,640],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"8gccIjcuf3gvaoEr","name":"OpenAi account"}},"typeVersion":1.2},{"id":"19c5ef66-410d-47fd-9b2a-19776c53a681","name":"Memory","type":"@n8n/n8n-nodes-langchain.memoryRedisChat","position":[-160,640],"parameters":{"sessionKey":"=handoff_{{ $('Telegram Trigger').first().json.message.chat.id }}_chat","sessionIdType":"customKey"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1.4},{"id":"814e464d-a2e0-4ae1-83d1-df3732d3b430","name":"Handoff Subworkflow","type":"n8n-nodes-base.executeWorkflowTrigger","position":[980,1040],"parameters":{"workflowInputs":{"values":[{"name":"chatId"},{"name":"sessionId"},{"name":"userId"},{"name":"username"},{"name":"summary"}]}},"typeVersion":1.1},{"id":"53c311ca-b7ad-4705-97c9-f6438a6c6b4e","name":"Telegram Trigger","type":"n8n-nodes-base.telegramTrigger","position":[-1000,820],"webhookId":"e905dd99-eefc-48ff-a62d-c7078e9bb216","parameters":{"updates":["message"],"additionalFields":{}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.1},{"id":"ea54c9f7-8ebc-4146-a4ec-6d05957f340d","name":"Send Response","type":"n8n-nodes-base.telegram","position":[1400,340],"webhookId":"55ecb0ba-72c8-4f16-a6c8-0c0bb8582554","parameters":{"text":"=Thank you. I've now transferred you to a human agent who will reach out to you. Once complete, you can come back to this chat to finish the process.","chatId":"={{ $('Telegram Trigger').first().json.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2},{"id":"7f895e2a-7aee-40be-a8b7-b2b0ff469b2d","name":"Switch Interaction","type":"n8n-nodes-base.switch","position":[-620,820],"parameters":{"rules":{"values":[{"outputKey":"Human","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"6bc61072-f7cf-4a6d-af81-36abede59d47","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.data }}","rightValue":"human"}]},"renameOutput":true},{"outputKey":"Bot","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"6882db64-b522-4895-8949-d98d87b53b49","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.data }}","rightValue":"bot"}]},"renameOutput":true}]},"options":{"fallbackOutput":"extra","renameFallbackOutput":"Onboarding"}},"typeVersion":3.2},{"id":"df203358-e6c7-4014-8e2b-ef934e331215","name":"Information Extractor","type":"@n8n/n8n-nodes-langchain.informationExtractor","position":[440,460],"parameters":{"text":"={{\n$json.data\n  .reverse()\n  .slice(0, 5)\n  .map(item => item.parseJson())\n  .map(item => `${item.type}: ${item.data.content}`)\n  .join('\\n')\n}}","options":{"systemPromptTemplate":"Analyse the conversation history and extract the required customer details. If not found, leave blank."},"attributes":{"attributes":[{"name":"firstname","required":true,"description":"first name of customer"},{"name":"lastname","required":true,"description":"last name of customer"},{"name":"address_and_postcode","required":true,"description":"address and postcode of customer"},{"name":"reason_for_call","required":true,"description":"a summary of the reason for the call"}]}},"typeVersion":1},{"id":"35bc11d2-6024-425b-ac67-a61ff26b9478","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[420,640],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"8gccIjcuf3gvaoEr","name":"OpenAi account"}},"typeVersion":1.2},{"id":"20d71c5f-6e84-4b45-b324-0706ecd3a681","name":"With Defaults","type":"n8n-nodes-base.code","position":[760,460],"parameters":{"mode":"runOnceForEachItem","jsCode":"return {\n  \"firstname\": \"\",\n  \"lastname\": \"\",\n  \"address_and_postcode\": \"\",\n  \"reason_for_call\": \"\",\n  ...$input.item.json.output,\n}"},"typeVersion":2},{"id":"76344f79-1afa-4fd9-9c01-ca3818f62f37","name":"Has All Criteria?","type":"n8n-nodes-base.if","position":[920,460],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"96d4a43f-aa0f-486a-b692-0105196d099a","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{ Object.values($json).every(val => Boolean(val)) }}","rightValue":""}]}},"typeVersion":2.2},{"id":"f76c1032-036b-46ad-91da-023d5af931fd","name":"Onboarding Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[-240,460],"parameters":{"text":"={{ $('Telegram Trigger').first().json.message.text }}","options":{"systemMessage":"=You are a prescreen assistant whose task is to get the following details from a customer before handing them over to a human agent.\n* first name\n* last name\n* address and postcode\n* reason for calling - capture exact wording if possible.\n\nOnce all data is gathered, hand the user off to a human agent."},"promptType":"define"},"typeVersion":1.8},{"id":"0a5b19a5-9c19-436c-b1d3-23d962efd23e","name":"Get Onboarding Chat History","type":"n8n-nodes-base.redis","position":[280,460],"parameters":{"key":"=handoff_{{ $('Telegram Trigger').first().json.message.chat.id }}_chat","options":{},"operation":"get","propertyName":"data"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1},{"id":"4f247eb3-78f0-4ec1-8713-1373da07b5f3","name":"After Sales Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[340,1000],"parameters":{"text":"={{ $('Telegram Trigger').item.json.message.text }}","options":{"systemMessage":"You are an aftersales agent helping the user answer questions about their recent purchase."},"promptType":"define"},"typeVersion":1.8},{"id":"bce26253-f7da-49e8-952b-52e14eb4f9b5","name":"Memory1","type":"@n8n/n8n-nodes-langchain.memoryRedisChat","position":[420,1180],"parameters":{"sessionKey":"=handoff_{{ $('Telegram Trigger').first().json.message.chat.id }}_chat2","sessionIdType":"customKey","contextWindowLength":30},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1.4},{"id":"51c4549b-559c-400d-9951-dde0953ade4c","name":"Model1","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[300,1180],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"8gccIjcuf3gvaoEr","name":"OpenAi account"}},"typeVersion":1.2},{"id":"63b8d9e8-7af2-4103-a365-ca5471bd7b36","name":"Handoff Tool","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[540,1180],"parameters":{"name":"handoff_to_human","workflowId":{"__rl":true,"mode":"id","value":"={{ $workflow.id }}"},"description":"Call this tool to handoff or defer to a human agent at the request of the customer. Ensure a summary of the reason for the handoff is obtained first.","workflowInputs":{"value":{"chatId":"={{ $('Telegram Trigger').first().json.message.chat.id.toString() }}","userId":"={{ $('Telegram Trigger').first().json.message.from.id.toString() }}","summary":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('summary', `Reason for human hand-off`, 'string') }}","username":"={{ $('Telegram Trigger').first().json.message.from.username }}","sessionId":"={{ $('Telegram Trigger').first().json.message.chat.id.toString() }}"},"schema":[{"id":"chatId","type":"string","display":true,"removed":false,"required":false,"displayName":"chatId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"sessionId","type":"string","display":true,"removed":false,"required":false,"displayName":"sessionId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"userId","type":"string","display":true,"removed":false,"required":false,"displayName":"userId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"username","type":"string","display":true,"removed":false,"required":false,"displayName":"username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"summary","type":"string","display":true,"removed":false,"required":false,"displayName":"summary","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2},{"id":"9a2b9077-0ead-4f2c-9e83-05ee341ff697","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-1080,580],"parameters":{"color":7,"width":660,"height":460,"content":"## 1. Check Interaction State For Incoming Message\n[Learn more about the telegram trigger](https://docs.n8n.io/integrations/builtin/trigger-nodes/n8n-nodes-base.telegramtrigger/)\n\nThis is an example of a state-based agent - the technique commonly known as a finite-state machine. This is a great way to really control the flow and direction of the conversation where there are requirements to collect data or perform steps in sequence. To manage the session state, we can use Redis and the session key will be the user's number."},"typeVersion":1},{"id":"ccca9a5c-595a-4c58-9316-933a8234ab91","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-380,260],"parameters":{"color":7,"width":560,"height":520,"content":"## 2. Onboarding Agent to Validate Customers\n[Read more about Agents](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent)\n\nThis agent unlike the common multi-tasking examples out there, is only tasked to handle the user's onboarding. In this way, we trade convenience for clutter but ensure the agent is less likely to stray from the desired path."},"typeVersion":1},{"id":"2d859430-1326-4cbc-a5cc-3af0d091e5c0","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[200,260],"parameters":{"color":7,"width":880,"height":520,"content":"## 3. Extract Customer Details from Conversation\n[Learn more about the Information Extractor](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.information-extractor)\n\nTo collect the user's details in a structured format, we can analyse the current conversation and extract the data with the Information Extractor node. This allows the conversation to remain free-form and avoids asking a question for each field. We use a code node to check if all details are captured."},"typeVersion":1},{"id":"754f0859-8af7-4a15-8e46-c9ad62b55bf3","name":"Handoff Subworkflow1","type":"n8n-nodes-base.executeWorkflow","position":[1220,340],"parameters":{"mode":"each","options":{"waitForSubWorkflow":false},"workflowId":{"__rl":true,"mode":"id","value":"={{ $workflow.id }}"},"workflowInputs":{"value":{"chatId":"={{ $('Telegram Trigger').first().json.message.chat.id.toString() }}","userId":"={{ $('Telegram Trigger').first().json.message.from.id.toString() }}","summary":"=name: {{ $json.firstname }} {{ $json.lastname }}\naddress: {{ $json.address_and_postcode }}\nsummary: {{ $json.reason_for_call }}","username":"={{ $('Telegram Trigger').first().json.message.from.username }}","sessionId":"={{ $('Telegram Trigger').first().json.message.chat.id.toString() }}"},"schema":[{"id":"chatId","type":"string","display":true,"required":false,"displayName":"chatId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"sessionId","type":"string","display":true,"required":false,"displayName":"sessionId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"userId","type":"string","display":true,"required":false,"displayName":"userId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"username","type":"string","display":true,"required":false,"displayName":"username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"summary","type":"string","display":true,"required":false,"displayName":"summary","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":true}},"typeVersion":1.2},{"id":"6f92128f-14dc-4b0a-b098-3d9535ac11e3","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1100,140],"parameters":{"color":7,"width":800,"height":640,"content":"## 4. Human Handoff when Criteria Met\n[Learn more about subworkflows](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.executeworkflow)\n\nHere, we initiate the hand-off which calls our hand-off subworkflow. Subworkflows can be a great way to run actions concurrently and without blocking the reply to the user. At this point, the session state would be set to \"human\" which means the human agent should take over."},"typeVersion":1},{"id":"14500c4f-da43-460f-bf4d-80d0a2f4537b","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-380,800],"parameters":{"color":7,"width":520,"height":440,"content":"## 5. Defer to Human\n\nWhen session state is \"human\", no further user messages can reach the agent. This is to ensure there isn't a parallel conversation happening which may confuse the human and agent."},"typeVersion":1},{"id":"4d74d479-8525-4b64-8291-e2b3058edeaa","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[160,800],"parameters":{"color":7,"width":720,"height":520,"content":"## 6. Interaction Switched Back to Bot\n[Read more about the Customer Workflow Tool](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.toolworkflow/)\n\nWhen the session state is \"bot\", it signals the human agent has \"transferred\" the user back to the bot and so can continue processing their messages. A Custom Workflow Tool is used to retrigger the hand-off process whenever the user requests for it."},"typeVersion":1},{"id":"a1c064d9-cc74-475d-b233-9deb4dfa81d7","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[920,820],"parameters":{"color":7,"width":1580,"height":560,"content":"## 7. Interaction Subworkflow\n[Learn more about n8n's human-in-the-loop feature](https://docs.n8n.io/advanced-ai/examples/human-fallback/)\n\nThe hand-off implementation here involves a \"human-in-the-loop\" feature of n8n - a feature which \"pauses\" an execution whilst running until a reply or action is sent back by the human. Sounds complicated but good to note that n8n handles this interaction seemlessly! Here, we're using it to allow the human agent to reliquish control of the conversation back to the AI agent. Additionally, the human agent's feedback is captured and added to the agent's memory to better assist the user afterwards."},"typeVersion":1},{"id":"33684768-2f21-4f30-9e56-934171b215fc","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[-1580,-260],"parameters":{"width":440,"height":1320,"content":"## Try it out\n### This n8n template demonstrates an approach to perform bot-to-human handoff using Human-in-the-loop functionality as a switch.\n\nIn this experiment, we play with the idea of states we want our agent to be in which controls it's interacton with the user.\n* **First state** - the agent is onboarding the user by collecting their details for a sales inquiry. After which, they are handed-off / transferred to a human to continue the call.\n* **Second state** - the agent is essentially \"deactivated\" as further messages to the bot will not reach it. Instead, a canned response is given to the user. The human agent must \"reactivate\" the bot by completing the human-in-the-loop form and give a summary of their conversation with the user.\n* **Third state** - the agent is \"reactivated\" with context of the human-to-user conversation and is set to provide after sales assistance. An tool is made available to the agent to again delegate back to the human agent when requested.\n\n### How it works\n* This template uses telegram to handle the interaction between the user and the agent.\n* Each user message is checked for a session state to ensure it is guided to the right stage of the conversation. For this, we can use Redis as a simple key-value store.\n* When no state is set, the user is directed through an onboarding step to attain their details. Once complete, the agent will \"transfer\" the user to a human agent - technically, all this involves is an update to the session state and a message to another chat forwarding the user's details.\n* During this \"human\" state, the agent cannot reply to the user and must wait until the human \"transfers\" the conversation back. The human can do this by replying to \"human-in-the-loop\" message with a summary of their conversation with the user. This session state now changes to \"bot\" and the context is implanted in the agent's memory so that the agent can respond to future questions.\n* At this stage of the conversation, the agent is now expected to handle and help the user with after-sales questions. The user can at anytime request transfer back to the human agent, repeating the previous steps as necessary.\n\n#### How to use\n* Plan your user journey! Here is a very basic example of a sales inquiry with at most 3 states. More thought should be developed when many more states are involved.\n* You may want to better log and manage session states so no user is left in limbo. Try connecting the user and sessions to your CRM.\n* Note, the Onboarding agent and After-Sales agent have separate chat memories. When adding more agents, it is recommend to continue having separate chat memories to help focus between states.\n\n### Need Help?\nJoin the [Discord](https://discord.com/invite/XPKeKXeB7d) or ask in the [Forum](https://community.n8n.io/)!\n\nHappy Hacking!"},"typeVersion":1},{"id":"187ca5ef-c804-4aca-8ad9-3c4b11676fbf","name":"Send Response2","type":"n8n-nodes-base.telegram","position":[2320,1040],"webhookId":"55ecb0ba-72c8-4f16-a6c8-0c0bb8582554","parameters":{"text":"=Hello again! I'm now ready to answer any remaining questions you may have.","chatId":"={{ $('Handoff Subworkflow').first().json.chatId }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2},{"id":"ab036106-84f2-4cf7-a5ad-7706a9e5ea0a","name":"Memory2","type":"@n8n/n8n-nodes-langchain.memoryRedisChat","position":[1980,1200],"parameters":{"sessionKey":"=handoff_{{ $('Handoff Subworkflow').first().json.chatId }}_chat2","sessionIdType":"customKey","contextWindowLength":30},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1.5},{"id":"9d9d1aee-5632-499c-968d-63a555cc58d8","name":"Update Agent Memory","type":"@n8n/n8n-nodes-langchain.memoryManager","position":[1980,1040],"parameters":{"mode":"insert","messages":{"messageValues":[{"type":"ai","message":"=Report from human agent says \"{{ $('Human Handoff using Send and Wait').first().json.data.text }}\"","hideFromUI":true},{"type":"ai","message":"Hello again! I'm now ready to answer any remaining questions you may have."}]}},"typeVersion":1.1},{"id":"8da2fefa-e51f-4258-8ded-e0f20db87641","name":"Send Response3","type":"n8n-nodes-base.telegram","position":[680,1000],"webhookId":"55ecb0ba-72c8-4f16-a6c8-0c0bb8582554","parameters":{"text":"={{ $json.output }}","chatId":"={{ $('Telegram Trigger').first().json.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2},{"id":"f027afe0-0fd2-47a2-a0f8-f0d78f8fbc18","name":"Get Canned Response","type":"n8n-nodes-base.telegram","position":[-180,1000],"webhookId":"55ecb0ba-72c8-4f16-a6c8-0c0bb8582554","parameters":{"text":"=This conversation has been handed-off to a human agent who will be in contact soon if not done so already. I cannot respond to your query until the human agent transfers you back to me.","chatId":"={{ $('Telegram Trigger').first().json.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2},{"id":"a1ada0c7-779e-44bc-bdbd-1d5285bedf3c","name":"Notify user","type":"n8n-nodes-base.telegram","position":[1180,1040],"webhookId":"55ecb0ba-72c8-4f16-a6c8-0c0bb8582554","parameters":{"text":"=You have now been transferred to a human. Unfortunately, I will not be able to respond until the human agent transfers you back to me.","chatId":"={{ $('Telegram Trigger').first().json.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2},{"id":"31287a38-e7a7-4518-9f54-6e6c9b2486fe","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[1520,1020],"parameters":{"width":220,"height":320,"content":"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### Add Human Chat ID\nThis is needed to notify the human agent."},"typeVersion":1},{"id":"a58a82b9-2c37-4137-9b3e-17479c78a2d2","name":"Memory3","type":"@n8n/n8n-nodes-langchain.memoryRedisChat","position":[1580,500],"parameters":{"sessionKey":"=handoff_{{ $('Telegram Trigger').first().json.message.chat.id }}_chat2","sessionIdType":"customKey","contextWindowLength":30},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1.5},{"id":"4d3d5b46-6e82-4b97-9e5f-76f02ff79ce5","name":"Update Agent Memory1","type":"@n8n/n8n-nodes-langchain.memoryManager","position":[1580,340],"parameters":{"mode":"insert","messages":{"messageValues":[{"type":"ai","message":"=The person I'm speaking to has the following details:\nfirstname: {{ $('Handoff Subworkflow1').first().json.firstname }}\nlastname: {{ $('Handoff Subworkflow1').first().json.firstname }}\nreason for call: {{ $('Handoff Subworkflow1').first().json.reason_for_call }}","hideFromUI":true}]}},"typeVersion":1.1},{"id":"ced46068-440b-46b4-aa51-b5bb9d59a004","name":"Continue Conversation","type":"n8n-nodes-base.telegram","position":[1220,580],"webhookId":"55ecb0ba-72c8-4f16-a6c8-0c0bb8582554","parameters":{"text":"={{ $('Onboarding Agent').first().json.output }}","chatId":"={{ $('Telegram Trigger').first().json.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2}],"pinData":{},"connections":{"Model":{"ai_languageModel":[[{"node":"Onboarding Agent","type":"ai_languageModel","index":0}]]},"Memory":{"ai_memory":[[{"node":"Onboarding Agent","type":"ai_memory","index":0}]]},"Model1":{"ai_languageModel":[[{"node":"After Sales Agent","type":"ai_languageModel","index":0}]]},"Memory1":{"ai_memory":[[{"node":"After Sales Agent","type":"ai_memory","index":0}]]},"Memory2":{"ai_memory":[[{"node":"Update Agent Memory","type":"ai_memory","index":0}]]},"Memory3":{"ai_memory":[[{"node":"Update Agent Memory1","type":"ai_memory","index":0}]]},"Notify user":{"main":[[{"node":"Set Interaction to Human","type":"main","index":0}]]},"Handoff Tool":{"ai_tool":[[{"node":"After Sales Agent","type":"ai_tool","index":0}]]},"Send Response":{"main":[[{"node":"Update Agent Memory1","type":"main","index":0}]]},"With Defaults":{"main":[[{"node":"Has All Criteria?","type":"main","index":0}]]},"Onboarding Agent":{"main":[[{"node":"Get Onboarding Chat History","type":"main","index":0}]]},"Telegram Trigger":{"main":[[{"node":"Get Interaction State","type":"main","index":0}]]},"After Sales Agent":{"main":[[{"node":"Send Response3","type":"main","index":0}]]},"Has All Criteria?":{"main":[[{"node":"Handoff Subworkflow1","type":"main","index":0}],[{"node":"Continue Conversation","type":"main","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Information Extractor","type":"ai_languageModel","index":0}]]},"Switch Interaction":{"main":[[{"node":"Get Canned Response","type":"main","index":0}],[{"node":"After Sales Agent","type":"main","index":0}],[{"node":"Onboarding Agent","type":"main","index":0}]]},"Handoff Subworkflow":{"main":[[{"node":"Notify user","type":"main","index":0}]]},"Update Agent Memory":{"main":[[{"node":"Send Response2","type":"main","index":0}]]},"Handoff Subworkflow1":{"main":[[{"node":"Send Response","type":"main","index":0}]]},"Get Interaction State":{"main":[[{"node":"Switch Interaction","type":"main","index":0}]]},"Information Extractor":{"main":[[{"node":"With Defaults","type":"main","index":0}]]},"Set Interaction to Bot":{"main":[[{"node":"Update Agent Memory","type":"main","index":0}]]},"Set Interaction to Human":{"main":[[{"node":"Human Handoff using Send and Wait","type":"main","index":0}]]},"Get Onboarding Chat History":{"main":[[{"node":"Information Extractor","type":"main","index":0}]]},"Human Handoff using Send and Wait":{"main":[[{"node":"Set Interaction to Bot","type":"main","index":0}]]}}}


name: Automate Product Training & Customer Support via WhatsApp, GPT-4 & Google Sheets
author_name: Dr. Firas
author_username: drfiras
categories: []
created_at: 2025-03-30T16:46:52.017Z
updated_at: 2025-03-30T16:46:52.017Z
url: https://n8n.io/workflows/3379
scraped_at: 2025-06-19 22:49:08
description:
  WhatsApp AI Agent: Auto-Train Product Data & Handle Customer Support

  Who Is This For

  This workflow is ideal for eCommerce founders, product managers, customer support teams, and automation builders who rely on WhatsApp to manage product information and interact with clients.

  It’s perfect for businesses that want to automate product data entry and support responses directly from WhatsApp messages using GPT-4 and Google Sheets.

  What Problem Does This Workflow Solve

  Manual Product Data Entry**: Collecting and organizing product data from links is tedious and error-prone.  
  Slow Customer Response Times**: Responding to client questions manually leads to delays and inconsistent support.  
  No Logging System for Issues**: Without automation, support issues often go undocumented, making it harder to learn and improve.

  What This Workflow Does

  Step 1 – Incoming Message Detection
  Listens for incoming messages via WhatsApp.
  If the message starts with train:, it routes to the product training process.
  Otherwise, it routes to the customer support assistant.

  Step 2 – Product Data Training
  Extracts URL** from the message using a regex script.
  Fetches HTML content** from the URL.
  Cleans HTML data** to extract readable product description.
  Saves raw data** (URL + description) into Google Sheets.
  Uses GPT-4** to enhance product data:  
    → Name, price (one-time or subscription), topic, and FAQs.  
  Updates the product row** in Google Sheets with structured information.

  Step 3 – Customer Support Flow
  Analyzes user messages with GPT-4 to understand the request or issue.
  Looks up relevant product info in Google Sheets.
  Detects potential problems (e.g. payment, login, delivery).
  Suggests an appropriate solution.
  Logs the problem, solution, and category to the Customer Issues sheet.
  Sends a response back to the client via WhatsApp.

  Step 4 – Client Response
  Sends the AI-generated response to the client via WhatsApp.
  Keeps the communication fast, clear, and professional.

  Setup Guide

  Prerequisites

  WhatsApp Business API access**
  OpenAI API Key**
  Google Account** with Google Sheets access
  A hosted instance of n8n (Cloud or self-hosted)

  Setup Steps

  Import the Workflow into your n8n instance.
  Connect your credentials for WhatsApp, OpenAI, and Google Sheets.
  Customize Google Sheet IDs and names as needed.
  Test by sending a train: message or a regular customer message to WhatsApp.
  Activate the workflow to make it live.

  How to Customize This Workflow

  Edit AI prompts** to reflect your product type, language style, or tone.
  Change the trigger keyword** (e.g. from train: to add: or anything else).
  Add integrations** like Notion, Airtable, or CRM tools.
  Expand the Sheets structure** with more product fields (e.g. stock status, image link).
  Add notifications** to Slack or email after product updates or issue logging.

  📄 Documentation: Notion Guide

  Need help customizing?
  Contact me for consulting and support : Linkedin / Youtube

nodes_used:
  ["n8n-nodes-base.googleSheets","n8n-nodes-base.httpRequest","n8n-nodes-base.whatsApp","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryBufferWindow"]

workflow_json:
  {"id":"GvlLeSOUPfar0DQS","meta":{"instanceId":"a2b23892dd6989fda7c1209b381f5850373a7d2b85609624d7c2b7a092671d44","templateCredsSetupCompleted":true},"name":"Automate Product Data Collection & Customer Support via WhatsApp + GPT-4 + Google Sheets","tags":[],"nodes":[{"id":"370611ee-2725-4ee4-a73a-68d4eaabfe3a","name":"WhatsApp Business Cloud","type":"n8n-nodes-base.whatsApp","position":[1020,220],"webhookId":"ef261fd4-e3b8-42e9-a0e2-2c3c44b6b15e","parameters":{"textBody":"={{ $json.output }}","operation":"send","phoneNumberId":"574583382412256","additionalFields":{},"recipientPhoneNumber":"+212722542056"},"credentials":{"whatsAppApi":{"id":"TzeEzaeiZOOqcLOZ","name":"WhatsApp account"}},"typeVersion":1},{"id":"30520fe8-a423-4942-85b2-9e8776b45939","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-740,-20],"parameters":{"width":400,"height":440,"content":"## 🟡 STEP 1 – Incoming WhatsApp Message\nListens for new WhatsApp messages.\nIf the message starts with train:, it triggers the product training flow.\nOtherwise, it goes to the customer support flow.\n**WhatsApp Business Cloud node** : [Here](https://www.notion.so/automatisation/WHATSAPP-WORKFLOW-1c63d6550fd980559679e7535938a68d?pvs=4#1c63d6550fd980f9a2a5e25a3654da82)"},"typeVersion":1},{"id":"d3259e0e-5368-407d-8ac6-993784c939c9","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-300,280],"parameters":{"color":6,"width":1180,"height":420,"content":"## 🔵 STEP 3 – Customer Support Flow\nTriggered when the message **does NOT start with `train:`**.\n\n1. **AI Analyzes the Message**  \n   Understands the customer's question or problem.\n\n2. **Fetch Product Data if Needed**  \n   Reads relevant product info from Google Sheets.\n\n3. **Detect Issues Automatically**  \n   Identifies if the user is facing a specific issue.\n\n4. **Suggest Solutions**  \n   Proposes a helpful, clear response to solve the issue.\n\n5. **Log Customer Problems**  \n   Saves the problem, suggested solution, and category.\n\n6. **Respond to the User**  \n   Sends a professional and helpful WhatsApp reply."},"typeVersion":1},{"id":"455ce4ab-6d14-4d4e-8ff8-04612cf532b9","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-300,-400],"parameters":{"color":3,"width":1180,"height":660,"content":"## 🔴 STEP 2 – Product Data Training (Triggered by train:)\nTriggered when the message starts with `train:`.\n**OpenAI API keys** : [Here](https://platform.openai.com/api-keys)\n\n\n\n\n\n\n\n\n\n\n\n\n1. **Extract URL from Message**  \n   Uses regex to detect and extract the product link.\n\n2. **Fetch HTML Content**  \n   Sends an HTTP request to retrieve the full page content.\n\n3. **Clean HTML Data**  \n   Strips HTML tags, scripts, and formats the text.\n\n4. **Save Raw Product Info**  \n   Appends the cleaned content and URL into Google Sheets.\n\n5. **AI: Enhance Product Details**  \n   - Extracts Product Name  \n   - Detects Price (subscription or one-time)  \n   - Identifies Product Topic  \n   - Generates FAQs\n\n6. **Update Product Sheet**  \n   Enriches the row in Sheets with structured product data.\n"},"typeVersion":1},{"id":"15251a04-a139-4a71-9e96-d5ecd9c2e66c","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[920,-20],"parameters":{"color":4,"width":320,"height":440,"content":"## 🟢 STEP 4 – Client Response\nFinal step of the flow.\n\n- Sends the AI-generated response back to the customer via WhatsApp.\n- Ensures the message is clear, helpful, and personalized."},"typeVersion":1},{"id":"f028f5a3-fed3-4f90-89cc-2af211da7362","name":"Incoming Message Trigger","type":"n8n-nodes-base.whatsAppTrigger","position":[-700,220],"webhookId":"48ce9bac-c7ea-4cb7-a40a-b010ea5ac743","parameters":{"options":{},"updates":["messages"]},"credentials":{"whatsAppTriggerApi":{"id":"zYvcHcxGBNdN9Ptf","name":"WhatsApp OAuth account"}},"typeVersion":1},{"id":"54edaa0c-005e-4810-a2fa-76fbcc009b2b","name":"Check If Training","type":"n8n-nodes-base.switch","position":[-520,220],"parameters":{"rules":{"values":[{"outputKey":"train","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"9865cb5b-33da-490c-afc3-186457d5b564","operator":{"type":"string","operation":"startsWith"},"leftValue":"={{ $json.messages[0].text.body }}","rightValue":"train:"}]},"renameOutput":true},{"outputKey":"text","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"5a9a1fee-b408-469f-a08c-e8d690fc9792","operator":{"type":"string","operation":"notStartsWith"},"leftValue":"={{ $json.messages[0].text.body }}","rightValue":"train:"}]},"renameOutput":true}]},"options":{}},"typeVersion":3.2},{"id":"b4187b28-efd9-46cb-8d1c-23d89d3f6125","name":"Extract URL from Text","type":"n8n-nodes-base.code","position":[-260,-320],"parameters":{"jsCode":"// Récupérer le texte à analyser depuis l'input\nconst texteExemple = $input.first().json.messages[0].text.body;\n\n// Expression régulière modifiée pour capturer les URL avec ou sans protocole\nconst regex = /((?:https?:\\/\\/)?(?:www\\.)?[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}(?:\\/\\S*)?)/g;\n\n// Extraction des URL à partir du texte\nconst matches = texteExemple.match(regex) || [];\n\n// Si des URL ont été trouvées, on les mappe en objets\nif (matches.length > 0) {\n    const output = matches.map(url => ({ url }));\n    return output;\n} else {\n    // Si aucune URL n'est trouvée, on retourne les items d'entrée pour que le workflow continue\n    return $input.all();\n}\n"},"typeVersion":2},{"id":"dbbcc8cf-2544-4de1-bcfd-6292d96a1017","name":"Fetch HTML Page","type":"n8n-nodes-base.httpRequest","position":[-100,-320],"parameters":{"url":"={{ $json.url }}","options":{"response":{"response":{"responseFormat":"text"}}}},"typeVersion":4.2},{"id":"91e711d0-26c0-41dd-a9c5-28100f0f44f6","name":"Clean HTML Content","type":"n8n-nodes-base.code","position":[60,-320],"parameters":{"jsCode":"// Exemple : récupération du contenu HTML depuis le premier item\n// Si vous avez un champ nommé \"html\" dans un noeud précédent.\nconst htmlContent = $input.first().json.html;\n\n// Fonction de nettoyage du HTML\nfunction nettoyerHTML(input) {\n  if (typeof input !== 'string') {\n    throw new Error(\"Expected HTML content as a string.\");\n  }\n  let cleanedText = input;\n\n  // 1. Retirer les liens <a> et leur contenu\n  cleanedText = cleanedText.replace(/<a[^>]*>.*?<\\/a>/gs, '');\n\n  // 2. Retirer <script>, <style>, commentaires, etc.\n  cleanedText = cleanedText.replace(/<script[^>]*>.*?<\\/script>/gs, '');\n  cleanedText = cleanedText.replace(/<style[^>]*>.*?<\\/style>/gs, '');\n  cleanedText = cleanedText.replace(/<!--[\\s\\S]*?-->/g, '');\n\n  // 3. Insérer des retours à la ligne pour certaines balises\n  cleanedText = cleanedText.replace(/<h[1-6][^>]*>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<\\/h[1-6]>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<p[^>]*>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<\\/p>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<ul[^>]*>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<\\/ul>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<ol[^>]*>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<\\/ol>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<li[^>]*>/gi, '- ');\n  cleanedText = cleanedText.replace(/<\\/li>/gi, '\\n');\n\n  // 4. Supprimer toutes les balises HTML restantes\n  cleanedText = cleanedText.replace(/<[^>]+>/g, '');\n\n  // 5. Supprimer (ou ajuster) les caractères spéciaux\n  cleanedText = cleanedText.replace(/[^\\w\\sÀ-ÖØ-öø-ÿ]+/g, '');\n\n  // 6. Normaliser les espaces multiples et trim\n  cleanedText = cleanedText.replace(/\\s+/g, ' ').trim();\n\n  return cleanedText;\n}\n\n// Nettoyage\nconst result = nettoyerHTML($input.first().json.data);\n\n// Retour d'un tableau contenant l'objet final\nreturn [\n  {\n    json: {\n      cleanedText: result\n    }\n  }\n];\n"},"typeVersion":2},{"id":"7e457450-42ef-417e-b5f9-3248c9c7c2ae","name":"Save Raw Product Info","type":"n8n-nodes-base.googleSheets","position":[240,-320],"parameters":{"columns":{"value":{"Product Link":"={{ $('Extract URL from Text').item.json.url }}","Product Description":"={{ $json.cleanedText }}"},"schema":[{"id":"Product Link","type":"string","display":true,"required":false,"displayName":"Product Link","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Name","type":"string","display":true,"required":false,"displayName":"Product Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Price","type":"string","display":true,"required":false,"displayName":"Product Price","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Description","type":"string","display":true,"required":false,"displayName":"Product Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Topic","type":"string","display":true,"required":false,"displayName":"Product Topic","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":689245338,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit#gid=689245338","cachedResultName":"Products"},"documentId":{"__rl":true,"mode":"list","value":"1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit?usp=drivesdk","cachedResultName":"Product Sales - AI Agent WhatsApp"}},"credentials":{"googleSheetsOAuth2Api":{"id":"51us92xkOlrvArhV","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"d3dfa439-4056-4ce9-b874-100500967de6","name":"OpenAI Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[320,-40],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"6h3DfVhNPw9I25nO","name":"OpenAi account"}},"typeVersion":1.2},{"id":"10217317-f6dd-4890-b05d-197d3d2adb79","name":"Short-Term Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[500,-40],"parameters":{"sessionKey":"={{ $('Incoming Message Trigger').item.json.messages[0].id }}","sessionIdType":"customKey","contextWindowLength":50},"typeVersion":1.3},{"id":"58ce0f46-fabc-4b6e-97d7-857dc6f1e568","name":"Update Product Sheet","type":"n8n-nodes-base.googleSheetsTool","position":[680,-40],"parameters":{"columns":{"value":{"F&Q":"={{ $fromAI(\"product_faq\", \"these are the most common questions users might have about the product, including answers if available\") }}\n","Product Link":"={{ $fromAI(\"product_url\",\"this is the website link of the product\") }}","Product Name":"={{ $fromAI(\"product_name\",\"this is the name of the product\") }}","Product Price":"={{ $fromAI(\"product_price\",\"this is the price of the product\") }}","Product Topic":"={{ $fromAI(\"product_topic\",\"this is the topic of the product that specifies what it is for, who it is for and what the key benefits are\") }}"},"schema":[{"id":"Product Link","type":"string","display":true,"removed":false,"required":false,"displayName":"Product Link","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Name","type":"string","display":true,"required":false,"displayName":"Product Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Price","type":"string","display":true,"required":false,"displayName":"Product Price","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Description","type":"string","display":true,"removed":true,"required":false,"displayName":"Product Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Topic","type":"string","display":true,"required":false,"displayName":"Product Topic","defaultMatch":false,"canBeUsedToMatch":true},{"id":"F&Q","type":"string","display":true,"removed":false,"required":false,"displayName":"F&Q","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["Product Link"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"appendOrUpdate","sheetName":{"__rl":true,"mode":"list","value":689245338,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit#gid=689245338","cachedResultName":"Products"},"documentId":{"__rl":true,"mode":"list","value":"1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit?usp=drivesdk","cachedResultName":"Product Sales - AI Agent WhatsApp"}},"credentials":{"googleSheetsOAuth2Api":{"id":"51us92xkOlrvArhV","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"020714ae-5668-4fa5-8ba8-f1e476a8060e","name":"AI Agent -  Customer Support Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[380,300],"parameters":{"text":"={{ $json.messages[0].text.body }}","options":{"systemMessage":"You are a helpful and intelligent customer support assistant.\n\nYou have access to a Google Sheets tool that allows you to read any content from a specific sheet to gather necessary information.\nNever mention to the user that you accessed Google Sheets to retrieve any data.\n\nYour main responsibilities:\n\nUnderstand the user’s request or issue.\n\nIf the user is asking about a product, retrieve the relevant product name, price, and details as needed.\n\nDetermine whether the product price is a subscription or a one-time payment, based on the description.\n\nIf you detect that the user is facing a problem:\n\nIdentify and describe the problem clearly.\n\nPropose a practical and helpful solution.\n\nLog this interaction by adding a new row to the Google Sheet with the following columns:\n\nProblem\n\nSuggested Solution\n\nCategory (e.g., payment, login, access, delivery, technical issue, etc.)\n\nBe professional, concise, and empathetic in your responses.\nAlways aim to resolve the issue or provide the next best action."},"promptType":"define"},"typeVersion":1.7},{"id":"53e49985-e1b9-48fd-9ea8-3352a63484e0","name":"AI Agent - Enhance Product Details","type":"@n8n/n8n-nodes-langchain.agent","position":[420,-320],"parameters":{"text":"=My product description :  {{ $json['Product Description'] }}\n\nMy product link : {{ $json['Product Link'] }}","options":{"systemMessage":"You are a helpful and intelligent assistant.\n\nYou receive the text content of a product page.\n\nYour tasks are:\n\nExtract the product name.\n\nExtract the product price, and determine whether it is a subscription or a one-time payment.\n\nIdentify the product topic.\n\nExtract the most frequently asked questions (FAQs) related to the product.\n\nYou have access to a Google Sheets tool that allows you to update specific columns and cells.\n\nAlways add the following data to the same row as the product URL in the Google Sheet:\n\nProduct Name\n\nProduct Price (with subscription/one-time label)\n\nProduct Topic\n\nFAQs\n\nBe accurate, structured, and consistent when filling in the sheet.\nDo not mention Google Sheets in your responses."},"promptType":"define"},"typeVersion":1.8},{"id":"194136b5-872a-492b-882b-d26a2890cbcf","name":"OpenAI Model1","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[220,560],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"6h3DfVhNPw9I25nO","name":"OpenAi account"}},"typeVersion":1.2},{"id":"efc89a9b-3141-4735-adaf-7b9e2b6879ed","name":"Conversation Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[400,560],"parameters":{"sessionKey":"={{ $json.messages[0].id }}","sessionIdType":"customKey","contextWindowLength":50},"typeVersion":1.3},{"id":"d1a21094-0237-4b17-818c-3af7760b405f","name":"Read Product Sheet","type":"n8n-nodes-base.googleSheetsTool","position":[560,560],"parameters":{"options":{"dataLocationOnSheet":{"values":{"readRowsUntil":"firstEmptyRow","rangeDefinition":"detectAutomatically"}}},"sheetName":{"__rl":true,"mode":"list","value":689245338,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit#gid=689245338","cachedResultName":"Products"},"documentId":{"__rl":true,"mode":"list","value":"1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit?usp=drivesdk","cachedResultName":"Product Sales - AI Agent WhatsApp"}},"credentials":{"googleSheetsOAuth2Api":{"id":"51us92xkOlrvArhV","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"2c2dcf9b-5578-4bd4-85b6-27621927a0a0","name":"Log Customer Issues","type":"n8n-nodes-base.googleSheetsTool","position":[740,560],"parameters":{"columns":{"value":{"Category":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Category', ``, 'string') }}","Solution":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Solution', ``, 'string') }}","Support Problem":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Support_Problem', ``, 'string') }}"},"schema":[{"id":"Support Problem","type":"string","display":true,"required":false,"displayName":"Support Problem","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Solution","type":"string","display":true,"required":false,"displayName":"Solution","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Category","type":"string","display":true,"required":false,"displayName":"Category","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":1725207764,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit#gid=1725207764","cachedResultName":"Customer Issues"},"documentId":{"__rl":true,"mode":"list","value":"1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit?usp=drivesdk","cachedResultName":"Product Sales - AI Agent WhatsApp"}},"credentials":{"googleSheetsOAuth2Api":{"id":"51us92xkOlrvArhV","name":"Google Sheets account"}},"typeVersion":4.5}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"2e8ea310-e164-4d5d-ae0b-ade129b07a4a","connections":{"OpenAI Model":{"ai_languageModel":[[{"node":"AI Agent - Enhance Product Details","type":"ai_languageModel","index":0}]]},"OpenAI Model1":{"ai_languageModel":[[{"node":"AI Agent -  Customer Support Agent","type":"ai_languageModel","index":0}]]},"Fetch HTML Page":{"main":[[{"node":"Clean HTML Content","type":"main","index":0}]]},"Check If Training":{"main":[[{"node":"Extract URL from Text","type":"main","index":0}],[{"node":"AI Agent -  Customer Support Agent","type":"main","index":0}]]},"Short-Term Memory":{"ai_memory":[[{"node":"AI Agent - Enhance Product Details","type":"ai_memory","index":0}]]},"Clean HTML Content":{"main":[[{"node":"Save Raw Product Info","type":"main","index":0}]]},"Read Product Sheet":{"ai_tool":[[{"node":"AI Agent -  Customer Support Agent","type":"ai_tool","index":0}]]},"Conversation Memory":{"ai_memory":[[{"node":"AI Agent -  Customer Support Agent","type":"ai_memory","index":0}]]},"Log Customer Issues":{"ai_tool":[[{"node":"AI Agent -  Customer Support Agent","type":"ai_tool","index":0}]]},"Update Product Sheet":{"ai_tool":[[{"node":"AI Agent - Enhance Product Details","type":"ai_tool","index":0}]]},"Extract URL from Text":{"main":[[{"node":"Fetch HTML Page","type":"main","index":0}]]},"Save Raw Product Info":{"main":[[{"node":"AI Agent - Enhance Product Details","type":"main","index":0}]]},"WhatsApp Business Cloud":{"main":[[]]},"Incoming Message Trigger":{"main":[[{"node":"Check If Training","type":"main","index":0}]]},"AI Agent -  Customer Support Agent":{"main":[[{"node":"WhatsApp Business Cloud","type":"main","index":0}]]},"AI Agent - Enhance Product Details":{"main":[[{"node":"WhatsApp Business Cloud","type":"main","index":0}]]}}}


name: Google Calendar Reminder System with GPT-4o and Telegram
author_name: Davide
author_username: n3witalia
categories: []
created_at: 2025-04-01T07:27:50.382Z
updated_at: 2025-04-01T07:27:50.382Z
url: https://n8n.io/workflows/3393
scraped_at: 2025-06-19 22:49:31
description:
  How many times have you missed a meeting or forgotten an appointment because a calendar reminder got lost in the noise? Traditional notifications are often dry, easy to ignore, or scattered across different apps—leaving you scrambling at the last minute.

  This smart Google Calendar workflow fixes that by sending you a clear, friendly reminder exactly 1 hour before your event starts—delivered through Telegram as if a personal assistant were looking out for you. Powered by AI, it transforms cold calendar alerts into warm, conversational nudges you won't ignore.

  Why This Works Better:  
  ✅ No More Overlooked Alerts – Consolidates reminders into one clear, accessible place (Telegram), so you never miss them.  
  ✅ Friendly & Engaging – AI transforms robotic calendar entries into natural, human-like reminders that are harder to ignore.  
  ✅ Works Everywhere – Whether you're on your phone, laptop, or tablet, you’ll get the same clear notification, no matter the platform.  

  How It Works
  Scheduled Trigger: The workflow starts with a Schedule Trigger node that runs every minute to check for upcoming events.
  Google Calendar Check: The "Get upcoming event" node queries Google Calendar for events starting within the next hour (between timeMin and timeMax).
  Duplicate Prevention: The "Already sent?" node ensures reminders are not sent multiple times for the same event by filtering out duplicates.
  AI-Powered Reminder: The "Secretary Agent" node, powered by GPT-4, crafts a friendly and professional reminder message. It includes event details like name, description, location, start/end time, and creator, formatted in a conversational tone.
  Telegram Notification: The final "Send reminder" node delivers the reminder via Telegram, ensuring the user receives it in a clear and accessible format.
  Set Up Steps
  Configure Schedule Trigger: Set the interval (e.g., every minute) to check for events.
  Connect Google Calendar: Link your Google Calendar account and specify the calendar to monitor.
  Set Up AI Agent: Customize the "Secretary Agent" with the provided system message to ensure reminders are warm, professional, and detailed.
  Link Telegram: Add your Telegram credentials and specify the CHAT_ID where reminders will be sent.
  Activate Workflow: Ensure the workflow is active and set to the correct timezone (e.g., Europe/Rome).
  Why It’s Useful
  Never Miss an Event**: Traditional calendar reminders can be easy to overlook, especially when scattered across platforms. This workflow consolidates reminders into a single, accessible channel (Telegram).
  Clear and Friendly**: The AI agent transforms generic calendar alerts into personalized, conversational reminders, making them harder to ignore.
  Cross-Platform Accessibility**: By delivering reminders via Telegram, users receive them in a consistent format, regardless of the device or platform they’re using. No more missed events due to unclear notifications!
  Need help customizing?  
  Contact me for consulting and support or add me on Linkedin.

nodes_used:
  ["n8n-nodes-base.telegram","n8n-nodes-base.googleCalendar","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi"]

workflow_json:
  {"id":"SvYHgLmzosuLAe4A","meta":{"instanceId":"a4bfc93e975ca233ac45ed7c9227d84cf5a2329310525917adaf3312e10d5462","templateCredsSetupCompleted":true},"name":"Google Calendar Event Reminder","tags":[],"nodes":[{"id":"dff5d952-23cb-4822-9aec-0dcae3de568a","name":"Schedule Trigger","type":"n8n-nodes-base.scheduleTrigger","disabled":true,"position":[-40,300],"parameters":{"rule":{"interval":[{"field":"minutes","minutesInterval":1}]}},"typeVersion":1.2},{"id":"a6de9944-1dd7-430e-a1d9-100710ddfa9c","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[700,500],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"CDX6QM4gLYanh0P4","name":"OpenAi account"}},"typeVersion":1.2},{"id":"6d2208a6-6000-4b6b-a82c-e346b7885409","name":"Get upcoming event","type":"n8n-nodes-base.googleCalendar","position":[240,300],"parameters":{"limit":5,"options":{},"timeMax":"={{ $now.plus({ hour: 1, minute:1 }) }}","timeMin":"={{ $now.plus({ hour: 1 }) }}","calendar":{"__rl":true,"mode":"list","value":"davide.boizza@gmail.com","cachedResultName":"davide.boizza@gmail.com"},"operation":"getAll"},"credentials":{"googleCalendarOAuth2Api":{"id":"8RFK3u13g2PJEGa9","name":"Google Calendar account"}},"typeVersion":1.3},{"id":"e6f6e744-60b0-4b22-93bc-f3ffcfac71f6","name":"Already sent?","type":"n8n-nodes-base.removeDuplicates","position":[480,300],"parameters":{"options":{},"operation":"removeItemsSeenInPreviousExecutions","dedupeValue":"={{ $json.id }}"},"typeVersion":2},{"id":"882d08f5-790a-40bb-bda5-60744d587633","name":"Secretary Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[720,300],"parameters":{"text":"=These are the details of the event/appointment:\n\nEvent Name: {{ $('Get upcoming event').item.json.summary }}\nDescription: {{ $('Get upcoming event').item.json.description }}\nLocation: {{ $('Get upcoming event').item.json.location }}\nStart: {{ $('Get upcoming event').item.json.start.dateTime }}\nEnd: {{ $('Get upcoming event').item.json.end.dateTime }}\nCreated by: {{ $('Get upcoming event').item.json.creator.email }}","options":{"systemMessage":"=## Core Identity\nYou are a professional and friendly virtual secretary, dedicated to reminder appointments with efficiency and a warm personal touch.\n\n## Communication Style\n- Communicate in a conversational, approachable manner\n- Maintain a balance between professional competence and friendly rapport\n- Use a tone that is informal yet precise\n- Inject occasional light humor and personality into interactions\n\n## Key Responsibilities\n1. Calendar Management\n   - Provide timely reminders and scheduling updates\n\n2. Communication Approach\n   - Respond promptly and clearly\n   - Maintain confidentiality and discretion\n\n## Interaction Guidelines\n- Use a friendly, conversational tone\n- Just describe the details of the event without asking questions\n\n## Tone and Language\n- Warm and approachable\n- Professional but not overly formal\n- Direct and clear in communication\n- Use simple, straightforward language\n- Show genuine care and attentiveness\n\nRemember: Your primary goal is to make the user's life easier, more organized, and less stressful through efficient and friendly administrative support."},"promptType":"define","hasOutputParser":true},"typeVersion":1.8},{"id":"82509a0f-9086-423e-8928-f882e59333b8","name":"Send reminder","type":"n8n-nodes-base.telegram","position":[1100,300],"webhookId":"dbb6a96e-db3b-4827-9455-a91007b89616","parameters":{"text":"={{ $json.output }}","chatId":"CHAT_ID","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"0hSq9VwaiJifiscT","name":"Telegram account"}},"typeVersion":1.2},{"id":"d08dd565-4718-4fbc-af7c-7a2e042c96f8","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-40,-140],"parameters":{"color":3,"width":620,"content":"## Google Calendar Event Reminder\nThis smart **Google Calendar** workflow fixes that by sending you a clear, friendly reminder exactly **1 hour before your event starts**—delivered through **Telegram** as if a personal assistant were looking out for you. Powered by **AI**, it transforms cold calendar alerts into warm, conversational nudges you won't ignore."},"typeVersion":1},{"id":"7a9379ca-f301-40b9-ae90-742663bbcdf2","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-40,40],"parameters":{"width":620,"height":140,"content":"## STEP 1\n- In the \"Get upcoming event\" node enter how much time before the event starts you want to be notified. It is currently set to 1 hour\n- In the Telegram node replace CHAT_ID with that of your personal Bot"},"typeVersion":1},{"id":"d7852912-6501-4a1b-8928-6eb890e4aea8","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[420,240],"parameters":{"width":220,"height":200,"content":"Prevent multiple reminders for the same event"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"timezone":"Europe/Rome","callerPolicy":"workflowsFromSameOwner","executionOrder":"v1"},"versionId":"d0dd74db-e96c-4a09-a8d1-6fb193b6e015","connections":{"Already sent?":{"main":[[{"node":"Secretary Agent","type":"main","index":0}]]},"Secretary Agent":{"main":[[{"node":"Send reminder","type":"main","index":0}]]},"Schedule Trigger":{"main":[[{"node":"Get upcoming event","type":"main","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Secretary Agent","type":"ai_languageModel","index":0}]]},"Get upcoming event":{"main":[[{"node":"Already sent?","type":"main","index":0}]]}}}


name: Parse Incoming Invoices From Outlook using AI Document Understanding
author_name: Jimleuk
author_username: jimleuk
categories: []
created_at: 2025-04-01T09:17:11.659Z
updated_at: 2025-04-01T09:17:11.659Z
url: https://n8n.io/workflows/3396
scraped_at: 2025-06-19 22:49:59
description:
  This n8n template monitors an Outlook mailbox for invoices, automatically parses/extracts data from them and then uploads the output to an Excel Workbook.

  One of my top workflow requests, this template can save many hours of manual labour for you or your finance/accounts team.

  How it works
  A scheduled trigger is set to fetch recent Outlook messages to the Accounts receivable mailbox.
  Each message is analysed to determine whether or not it from a supplier and is issuing/contains an invoice.
  For each valid message, the attachments are downloaded and non-invoice documents are filtered out via AI Vision classification.
  Invoices are then processed through a AI vision model again to extract the details.
  The extracted data can then be used for reconciliation or otherwise. For this demonstration, we'll just append the row to an Excel sheet for now.

  How to use
  Ensure your Microsoft365 credential points to the correct mailbox. If a shared folder is used, toggle "shared folder" option to "on" and for the principal ID, use the email address.
  If you receive lots of other types of messages such as replies and forwards, you may want to implement additional checks to prevent processing invoices twice. The "remove duplicates" node can help with this.

  Requirements
  Outlook for Mailbox
  Google Gemini for Document Understanding and Invoice Extraction
  Excel for Data Storage

  Customising this workflow
  Note the assumption for this template is that all invoices will come as a PDF attachment. In real life, this is rarely the case! Adding in document conversion to cover all invoice formats.
  Human feedback is also an important factor in AI workflows. Try tagging emails as a way to notify team members that the invoice was processed.

nodes_used:
  ["n8n-nodes-base.httpRequest","n8n-nodes-base.microsoftExcel","n8n-nodes-base.microsoftOutlook","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.lmChatGoogleGemini","@n8n/n8n-nodes-langchain.textClassifier"]

workflow_json:
  {"meta":{"instanceId":"408f9fb9940c3cb18ffdef0e0150fe342d6e655c3a9fac21f0f644e8bedabcd9","templateCredsSetupCompleted":true},"nodes":[{"id":"78bb4afe-ccc6-4b5e-90ba-50253f761f14","name":"Split Attachments","type":"n8n-nodes-base.code","position":[-80,140],"parameters":{"jsCode":"let results = [];\n\nfor (const item of $input.all()) {\n    for (key of Object.keys(item.binary)) {\n        results.push({\n            json: {\n                fileName: item.binary[key].fileName\n            },\n            binary: {\n                data: item.binary[key],\n            }\n        });\n    }\n}\n\nreturn results;"},"typeVersion":2},{"id":"48a79e8c-27c2-4cdb-a6f7-241158c10962","name":"Download Attachments","type":"n8n-nodes-base.microsoftOutlook","position":[-260,140],"webhookId":"2eb57df9-1579-4af2-a30e-f412b268aba2","parameters":{"options":{"downloadAttachments":true},"messageId":{"__rl":true,"mode":"id","value":"={{ $json.id }}"},"operation":"get"},"credentials":{"microsoftOutlookOAuth2Api":{"id":"EWg6sbhPKcM5y3Mr","name":"Microsoft Outlook account"}},"typeVersion":2},{"id":"7dda1618-dfa7-4325-b5ff-7935602a3043","name":"Parse Output","type":"n8n-nodes-base.set","position":[680,400],"parameters":{"mode":"raw","options":{},"jsonOutput":"={{\n{\n  invoice: $json.candidates[0].content.parts[0].text.parseJson(),\n  email: {\n    ...$('Message Ref').first().json,\n    body: null\n  }\n}\n}}"},"typeVersion":3.4},{"id":"4d45cf33-5a14-4fe4-9485-38de901113aa","name":"For Each Message","type":"n8n-nodes-base.splitInBatches","position":[-640,140],"parameters":{"options":{}},"typeVersion":3},{"id":"b5c70065-3ed8-4024-9a10-247810c062a4","name":"Message Ref","type":"n8n-nodes-base.noOp","position":[-440,140],"parameters":{},"typeVersion":1},{"id":"cafcf919-25c3-46bd-8dd3-8cc0201c93cb","name":"Message Classifier","type":"@n8n/n8n-nodes-langchain.textClassifier","position":[-1160,140],"parameters":{"options":{"fallback":"other"},"inputText":"=from: {{ $json.from.emailAddress.address }} <{{ $json.from.emailAddress.address }}>\nsubject: {{ $json.subject }}\n<message>\n{{ $json.markdown.split('\\n**From**')[0].trim() }}\n</message>","categories":{"categories":[{"category":"invoice","description":"Message is an invoice is being issued"}]}},"typeVersion":1},{"id":"f97f9b24-828b-4dd8-a0e8-b7ab670403a8","name":"Extract from File","type":"n8n-nodes-base.extractFromFile","position":[-440,340],"parameters":{"options":{},"operation":"binaryToPropery"},"typeVersion":1},{"id":"99d49549-af7c-46aa-b321-2b9955333812","name":"Markdown","type":"n8n-nodes-base.markdown","position":[-1340,140],"parameters":{"html":"={{ $json.body.content }}","options":{},"destinationKey":"markdown"},"typeVersion":1},{"id":"18455ee7-e87b-433c-baef-28444358e486","name":"Empty Response","type":"n8n-nodes-base.set","position":[680,600],"parameters":{"mode":"raw","options":{},"jsonOutput":"={{\n{\n  invoice: null,\n  email: {\n    ...$('Message Ref').first().json,\n    body: null\n  }\n}\n}}"},"typeVersion":3.4},{"id":"d0b4bab2-5955-4d05-8e4f-4a23fac98c45","name":"Wait","type":"n8n-nodes-base.wait","position":[880,600],"webhookId":"6dae0a77-74f4-4d85-a58b-e55c44fbea58","parameters":{"amount":1},"typeVersion":1.1},{"id":"2600020d-9751-44df-abcd-48026c21f592","name":"Filter Invoices","type":"n8n-nodes-base.filter","position":[-80,340],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"5240de52-3b02-4151-8c2b-b0522582700e","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{\n(function(output) {\n  return output.is_invoice && output.is_issued_to_company;\n})(\n  $json.candidates[0].content.parts[0].text.parseJson()\n)\n}}","rightValue":""}]}},"typeVersion":2.2,"alwaysOutputData":true},{"id":"b31d359e-d949-4d56-b32e-c49b35124ff7","name":"Has Invoice?","type":"n8n-nodes-base.if","position":[280,400],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"57f433cd-5861-434f-80f2-ce28d7c22c26","operator":{"type":"object","operation":"notEmpty","singleValue":true},"leftValue":"={{ $input.first().json }}","rightValue":""}]}},"typeVersion":2.2},{"id":"857e2282-d7f7-438b-be87-a1c36986cfc0","name":"Schedule Trigger","type":"n8n-nodes-base.scheduleTrigger","position":[-1820,120],"parameters":{"rule":{"interval":[{"field":"hours"}]}},"typeVersion":1.2},{"id":"7292a6cc-3b59-4d9b-b87d-3ba55bbc0c67","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-780,-120],"parameters":{"color":7,"width":950,"height":680,"content":"## 2. Classify If Attachment is Invoice\n[Learn more about the Outlook node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.microsoftoutlook)\n\nFor each qualifying message, we will need to know which of the attachments contained are actual invoice documents. To do this, we can use Google Gemini's docuemnt understanding capabilities to validate this test. We're using Gemini specifically in this case because at time of writing, Gemini is the only one of the few LLM providers that are currently accepting PDF documents. If you're not using Gemini, you may need to convert the PDF document to an image first - [check out an example of this here](https://n8n.io/workflows/2421-transcribing-bank-statements-to-markdown-using-gemini-vision-ai/)."},"typeVersion":1},{"id":"ed35c1dc-625d-4ffb-b186-fad514f6df81","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[200,180],"parameters":{"color":7,"width":850,"height":580,"content":"## 3. Extract Invoice Details\n[Learn more about the HTTP Request node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.httprequest/)\n\nWith our invoice PDFs ready to go, we'll again use the Gemini API to extract the required details from them. I'm using the HTTP request node because unfortunately, Gemini works best for data extraction when using the API's \"generationConfig\" parameter which isn't supported in n8n's native AI nodes. The output is then merged with the original email to keep the reference between them."},"typeVersion":1},{"id":"42a9036c-8040-41a7-9366-658ba3e31c70","name":"Get Recent Messages","type":"n8n-nodes-base.microsoftOutlook","position":[-1540,140],"webhookId":"e3957f65-145c-4c0d-ac66-31342a1bc888","parameters":{"fields":["body","categories","conversationId","from","hasAttachments","internetMessageId","sender","subject","toRecipients","receivedDateTime","webLink"],"output":"fields","options":{},"filtersUI":{"values":{"filters":{"receivedAfter":"={{ $now.minus({ \"hour\": 1 }).toISO() }}","hasAttachments":true,"foldersToInclude":["AAMkAGZkNmEzOTVhLTk3NDQtNGQzNi1hNDY2LTE2MWFlMzUyNTczMgAuAAAAAAA27qsaXv92QoGqcRnqoMpSAQDhSgSaDoa3Sp4gzAabpsdOAAAAAAEMAAA="]}}},"operation":"getAll","returnAll":true},"credentials":{"microsoftOutlookOAuth2Api":{"id":"EWg6sbhPKcM5y3Mr","name":"Microsoft Outlook account"}},"typeVersion":2},{"id":"86838ba4-0d57-4571-983f-c17005f39333","name":"Model","type":"@n8n/n8n-nodes-langchain.lmChatGoogleGemini","position":[-1080,280],"parameters":{"options":{},"modelName":"models/gemini-2.0-flash"},"credentials":{"googlePalmApi":{"id":"dSxo6ns5wn658r8N","name":"Google Gemini(PaLM) Api account"}},"typeVersion":1},{"id":"8ecb7298-3512-40fe-b2bc-70fb4ed5965d","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-1620,-120],"parameters":{"color":7,"width":810,"height":560,"content":"## 1. Check for Invoice Emails\n[Learn more about the text classifier node](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.text-classifier/)\n\nThe Outlook node fetches all inbox messages within the last hour and classifies each message prior to downloading the attachments. This is a really good early check to reduce the comsumption of resources. In this use-case, using AI for contextual reasoning regarding the intent of the email can be much more powerful than simple keyword matching. The latter is more prone to matching false positives.\n*Note: we're not using the Outlook Trigger node because it doesn't allow setting for dateTime filters.*"},"typeVersion":1},{"id":"a3c28ab3-ecab-46fd-86bb-62bf8a222f37","name":"Microsoft Excel 365","type":"n8n-nodes-base.microsoftExcel","position":[420,-40],"parameters":{"options":{},"fieldsUi":{"values":[{}]},"resource":"worksheet","workbook":{"__rl":true,"mode":"id","value":"ABCDEFGHIJ"},"operation":"append","worksheet":{"__rl":true,"mode":"id","value":"{00000000-0001-0000-0000-000000000000}"}},"credentials":{"microsoftExcelOAuth2Api":{"id":"56tIUYYVARBe9gfX","name":"Microsoft Excel account"}},"typeVersion":2.1},{"id":"69f2a975-ab91-4cbc-be72-633c4601bf6f","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[200,-220],"parameters":{"color":7,"width":530,"height":380,"content":"## 4. Upload to Excel Workbook\n[Read more about the Excel node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.microsoftexcel/)\n\nFinally to capture the data, we can map these to an Excel workflow which can be reviewed by a human before it enters the accounting system."},"typeVersion":1},{"id":"68f7c7f3-5ddd-4291-adb3-78f3a297fd8e","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-2120,-660],"parameters":{"width":480,"height":960,"content":"## Try it out\n### This n8n template monitors an Outlook mailbox for invoices, automatically parses/extracts data from them and then uploads the output to an Excel Workbook.\n\nOne of my top workflow requests, this template can save in order of 100s of hours of manual labour for you or your finance team.\n\n### How it works\n* A scheduled trigger is set to fetch recent Outlook messages to the Accounts receivable mailbox.\n* Each message is analysed to determine whether or not it from a supplier and is issuing/contains an invoice.\n* For each valid message, the attachments are downloaded and non-invoice documents are filtered out via AI Vision classification.\n* Invoices are then processed through a AI vision model again to extract the details.\n* The extracted data can then be used for reconciliation or otherwise. For this demonstration, we'll just append the row to an Excel sheet for now.\n\n### How to use\n* Ensure your Microsoft365 credential points to the correct mailbox. If a shared folder is used, toggle \"shared folder\" option to \"on\" and for the principal ID, use the email address.\n* If you receive lots of other types of messages such as replies and forwards, you may want to implement additional checks to prevent processing invoices twice. The \"remove duplicates\" node can help with this.\n\n### Need Help?\nJoin the [Discord](https://discord.com/invite/XPKeKXeB7d) or ask in the [Forum](https://community.n8n.io/)!\n\nHappy Hacking!"},"typeVersion":1},{"id":"a55323b4-2079-4a7c-8ba2-f20ef0930b55","name":"Invoice Classifier With Gemini 2.0","type":"n8n-nodes-base.httpRequest","position":[-260,340],"parameters":{"url":"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent","method":"POST","options":{},"jsonBody":"={{\n{\n  \"contents\": [\n    {\n      \"parts\": [\n        {\n          \"inline_data\": {\n            \"mime_type\": $('Split Attachments').item.binary.data.mimeType,\n            \"data\": $json.data\n          }\n        },\n        {\n          \"text\": `You are an accounts receivable agent who is helping to identify if the document is an invoice, the invoice's supplier is not our company and the invoice is issued to our company.`\n        }\n      ]\n    }\n  ],\n  \"generationConfig\": {\n    \"response_mime_type\": \"application/json\",\n    \"response_schema\": {\n      \"type\": \"OBJECT\",\n      \"required\": [\n        \"is_invoice\",\n        \"is_issued_to_company\"\n      ],\n      \"properties\": {\n        \"is_invoice\": { \"type\": \"boolean\" },\n        \"is_issued_to_company\": { \"type\": \"boolean\" }\n      }\n    }\n  }\n}\n}}","sendBody":true,"specifyBody":"json","authentication":"predefinedCredentialType","nodeCredentialType":"googlePalmApi"},"credentials":{"googlePalmApi":{"id":"dSxo6ns5wn658r8N","name":"Google Gemini(PaLM) Api account"}},"executeOnce":false,"retryOnFail":false,"typeVersion":4.2},{"id":"f696737d-cddf-411b-a427-cc72bd68d248","name":"File-Based OCR with Gemini 2.0","type":"n8n-nodes-base.httpRequest","onError":"continueErrorOutput","position":[480,400],"parameters":{"url":"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent","method":"POST","options":{},"jsonBody":"={{\n{\n  \"contents\": [\n    {\n      \"parts\": [\n        {\n          \"inline_data\": {\n            \"mime_type\": $('Split Attachments').item.binary.data.mimeType,\n            \"data\": $('Extract from File').item.json.data\n          }\n        },\n        {\n          \"text\": `You are an accounts receivable agent who is helping to extract information from a supplier's invoice issued to our company.`\n        }\n      ]\n    }\n  ],\n  \"generationConfig\": {\n    \"response_mime_type\": \"application/json\",\n    \"response_schema\": {\n      \"type\": \"OBJECT\",\n      \"required\": [\n        \"invoice_number\",\n        \"invoice_date\",\n        \"invoice_amount\",\n        \"invoice_due_date\",\n        \"supplier_name\",\n        \"supplier_address\",\n        \"supplier_telephone\",\n        \"supplier_email\",\n        \"booking_number\",\n        \"booking_date\",\n        \"booking_name\",\n        \"guest_name\",\n        \"guest_quantity\",\n        \"services\"\n      ],\n      \"properties\": {\n        \"invoice_number\": { \"type\": \"string\" },\n        \"invoice_date\": { \"type\": \"string\", \"nullable\": true },\n        \"invoice_amount\": { \"type\": \"number\", \"nullable\": true },\n        \"invoice_due_date\": { \"type\": \"string\", \"nullable\": true },\n        \"recipient_name\": { \"type\": \"string\", \"nullable\": true },\n        \"recipient_address\": { \"type\": \"string\", \"nullable\": true },\n        \"recipient_company_number\": { \"type\": \"string\", \"nullable\": true },\n        \"supplier_name\": { \"type\": \"string\", \"nullable\": true },\n        \"supplier_address\": { \"type\": \"string\", \"nullable\": true },\n        \"supplier_telephone\": { \"type\": \"string\", \"nullable\": true },\n        \"supplier_email\": { \"type\": \"string\", \"nullable\": true },\n        \"supplier_company_number\": { \"type\": \"string\", \"nullable\": true },\n        \"booking_number\": { \"type\": \"string\", \"nullable\": true },\n        \"booking_date\": { \"type\": \"string\", \"nullable\": true },\n        \"booking_name\": { \"type\": \"string\", \"nullable\": true },\n        \"guest_name\": { \"type\": \"string\", \"nullable\": true },\n        \"guest_quantity\": { \"type\": \"number\", \"nullable\": true },\n        \"services\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"object\",\n            \"required\": [],\n            \"properties\": {\n              \"name\": { \"type\": \"string\" },\n              \"date\": { \"type\": \"string\", \"nullable\": true },\n              \"description\": { \"type\": \"string\", \"nullable\": true },\n              \"quantity\": { \"type\": \"number\", \"nullable\": true },\n              \"total\": { \"type\": \"number\" }\n            }\n          }\n        }\n      }\n    }\n  }\n}\n}}","sendBody":true,"specifyBody":"json","authentication":"predefinedCredentialType","nodeCredentialType":"googlePalmApi"},"credentials":{"googlePalmApi":{"id":"dSxo6ns5wn658r8N","name":"Google Gemini(PaLM) Api account"}},"executeOnce":false,"retryOnFail":false,"typeVersion":4.2},{"id":"1d76c0c8-a03b-4f0c-b76d-53369ab5d6e8","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[760,-220],"parameters":{"color":5,"width":400,"height":140,"content":"### Where Next? It's Up to You!\nThis template is deliberately cut short to demonstrate the build but should be easily modified to upload directly to an accounting system or even extended for other tasks such as invoice reconciliation and more."},"typeVersion":1}],"pinData":{},"connections":{"Wait":{"main":[[{"node":"For Each Message","type":"main","index":0}]]},"Model":{"ai_languageModel":[[{"node":"Message Classifier","type":"ai_languageModel","index":0}]]},"Markdown":{"main":[[{"node":"Message Classifier","type":"main","index":0}]]},"Message Ref":{"main":[[{"node":"Download Attachments","type":"main","index":0}]]},"Has Invoice?":{"main":[[{"node":"File-Based OCR with Gemini 2.0","type":"main","index":0}],[{"node":"Empty Response","type":"main","index":0}]]},"Parse Output":{"main":[[{"node":"Wait","type":"main","index":0}]]},"Empty Response":{"main":[[{"node":"Wait","type":"main","index":0}]]},"Filter Invoices":{"main":[[{"node":"Has Invoice?","type":"main","index":0}]]},"For Each Message":{"main":[[{"node":"Microsoft Excel 365","type":"main","index":0}],[{"node":"Message Ref","type":"main","index":0}]]},"Schedule Trigger":{"main":[[{"node":"Get Recent Messages","type":"main","index":0}]]},"Extract from File":{"main":[[{"node":"Invoice Classifier With Gemini 2.0","type":"main","index":0}]]},"Split Attachments":{"main":[[{"node":"Extract from File","type":"main","index":0}]]},"Message Classifier":{"main":[[{"node":"For Each Message","type":"main","index":0}],[]]},"Get Recent Messages":{"main":[[{"node":"Markdown","type":"main","index":0}]]},"Download Attachments":{"main":[[{"node":"Split Attachments","type":"main","index":0}]]},"File-Based OCR with Gemini 2.0":{"main":[[{"node":"Parse Output","type":"main","index":0}],[{"node":"Empty Response","type":"main","index":0}]]},"Invoice Classifier With Gemini 2.0":{"main":[[{"node":"Filter Invoices","type":"main","index":0}],[]]}}}


name: Analyze Crypto Markets with the AI-Powered CoinMarketCap Data Analyst
author_name: Don Jayamaha Jr
author_username: don-the-gem-dealer
categories: []
created_at: 2025-04-03T13:53:03.108Z
updated_at: 2025-04-03T13:53:03.108Z
url: https://n8n.io/workflows/3425
scraped_at: 2025-06-19 22:49:31
description:
  Meet your AI-powered crypto data analyst—fully integrated with CoinMarketCap APIs.  

  This workflow acts as the supervisor agent for a multi-agent architecture built in n8n, connecting three powerful sub-agents to extract real-time insights from centralized and decentralized markets. It’s the ultimate tool for crypto traders, analysts, developers, and researchers who need strategic multi-source intelligence—all through Telegram.

  This workflow requires 3 sub-agent templates to function correctly. See below.

  🔌 Required Sub-Workflows (Install First)

  CoinMarketCap Crypto Agent Tool  
     → Token prices, metadata, conversions, listings

  CoinMarketCap Exchange & Community Agent Tool  
     → Exchange info, token holdings, Fear & Greed index

  CoinMarketCap DEXScan Agent Tool  
     → DEX trading pairs, liquidity, OHLCV data

   Download all from my Creator Profile:  
   https://n8n.io/creators/don-the-gem-dealer/

  What Makes This Workflow Special?

  This is not just another API wrapper—it’s an intelligent routing agent powered by GPT-4o-mini, capable of:

  Understanding complex user queries  
  Choosing the appropriate tool workflow  
  Structuring the API request  
  Executing sub-workflows  
  Formatting the output  
  Returning insights via Telegram

  It connects three domains of market data:
  Cryptocurrencies (CEX)**
  Exchanges & Sentiment**
  DEX trading data**

  🔍 What You Can Do  

  💰 Token Intelligence
  Get token metadata, price, volume, supply
  Compare rankings and conversions

  🏦 Exchange Insights
  View assets held by exchanges
  Track the CMC 100 Index and Fear & Greed Score

  🌐 DEX Market Analysis
  Analyze pair quotes, historical OHLCV, live trades
  Discover the top DEXs by volume across blockchains

  ✅ Example Questions to Ask
  “What’s the market cap of Ethereum today?”  
  “Show liquidity and volume for SOL/USDT on Solana”  
  “Get token holdings for Binance”  
  “Compare BTC price on Uniswap vs Binance”  
  “What’s the Fear & Greed index right now?”

  🛠️ Setup Instructions

  Create Telegram Bot  
     Use @BotFather to get your bot token.

  Get CoinMarketCap API Key  
     Apply here: https://coinmarketcap.com/api/

  Install Sub-Agent Templates  
     Required:
       Crypto Agent Tool  
       Exchange & Community Tool  
       DEXScan Tool

  Configure Credentials in n8n  
     Add both Telegram and CoinMarketCap keys as HTTP Header Auth.

  Deploy & Test  
     Ask your Telegram bot: “Top 10 tokens by 24h volume” or “Convert 5 ETH to USD”

  Workflow Architecture

  AI Brain**: GPT-4o-mini  
  Memory**: Windowed buffer memory via sessionId  
  Tool Agents**:  
     toolWorkflow() → routes requests to the appropriate sub-agent  
     Executes real-time API queries and returns structured output

  Included Sticky Notes  
  System Overview**  
  Error Handling Guide (200, 400, 401, 429, 500)**  
  Step-by-Step Usage Instructions**  
  Prompt Examples + API Docs**  
  Legal & Licensing Notes**

  Your crypto insights—smarter, faster, and all in one Telegram message.

nodes_used:
  ["n8n-nodes-base.telegram","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryBufferWindow","@n8n/n8n-nodes-langchain.toolWorkflow"]

workflow_json:
  {"id":"mE7Zvhv1lOd4Q3xY","meta":{"instanceId":"a5283507e1917a33cc3ae615b2e7d5ad2c1e50955e6f831272ddd5ab816f3fb6"},"name":"CoinMarketCap_AI_Data_Analyst_Agent","tags":[],"nodes":[{"id":"1eab0bd5-8f9c-4bc4-92b7-50779baa505c","name":"Telegram Send Message","type":"n8n-nodes-base.telegram","position":[1180,0],"webhookId":"0eeae020-ed6f-4900-ae38-d646d893171d","parameters":{"text":"={{ $json.output }}","chatId":"={{ $('Telegram Input').item.json.message.chat.id }}","additionalFields":{}},"credentials":{"telegramApi":{"id":"R3vpGq0SURbvEw2Z","name":"Telegram account"}},"typeVersion":1},{"id":"fd89fa7e-c4e1-4559-a0cc-42beaeccefb4","name":"Adds SessionId","type":"n8n-nodes-base.set","position":[280,0],"parameters":{"options":{},"assignments":{"assignments":[{"id":"b5c25cd4-226b-4778-863f-79b13b4a5202","name":"sessionId","type":"string","value":"={{ $json.message.chat.id }}"}]},"includeOtherFields":true},"typeVersion":3.4},{"id":"aea9adc8-8215-4459-9bf0-5a6b6364ffcc","name":"CoinMarketCap AI Data Analyst Agent","type":"@n8n/n8n-nodes-langchain.agent","notes":"{{ $json.sessionId }}","position":[660,0],"parameters":{"text":"={{ $json.message.text }}","options":{"systemMessage":"You are the **CoinMarketCap AI Data Analyst**, a powerful, multi-source crypto intelligence system that integrates three specialized agents:  \n- **CoinMarketCap Crypto Agent**  \n- **CoinMarketCap Exchange & Community Agent**  \n- **CoinMarketCap DEXScan Agent**\n\nYour job is to provide accurate, real-time, and strategic insights into the cryptocurrency landscape across centralized and decentralized platforms.\n\n---\n\n### 🛠️ Tools and Agent Capabilities\n\nYou have access to a suite of **live CoinMarketCap APIs** organized by sub-agents. Each tool is mapped to an endpoint and validated for parameter safety to avoid 400 errors.\n\n---\n\n#### 🔹 1. CoinMarketCap Crypto Agent\n\n**Focus:** Cryptocurrency-level data, listings, quotes, and conversions.\n\n**Tools:**\n- `Crypto Map` – Get coin IDs, names, symbols  \n- `Crypto Info` – Metadata like whitepapers, socials  \n- `Crypto Listings` – Top market cap coins  \n- `Quotes Latest` – Live price, volume, market cap  \n- `Global Metrics` – Total market stats, BTC dominance  \n- `Price Conversion` – Convert one asset to another  \n\n✅ Use for:  \n“Top 10 coins by market cap,” “Convert 5 ETH to USD,” “BTC volume today,” “Whitepaper for SOL”\n\n---\n\n#### 🔹 2. CoinMarketCap Exchange & Community Agent\n\n**Focus:** Exchange intel, community sentiment, and market behavior.\n\n**Tools:**\n- `Exchange Map` – Discover exchanges and get IDs  \n- `Exchange Info` – Metadata like launch date, country, links  \n- `Exchange Assets` – Exchange token holdings & wallets  \n- `CMC 100 Index` – Latest CMC 100 index constituents  \n- `Fear and Greed Index` – Market sentiment tracker  \n\n✅ Use for:  \n“Which tokens does Binance hold?” “Current crypto sentiment” “Top 100 CMC coins”\n\n---\n\n#### 🔹 3. CoinMarketCap DEXScan Agent\n\n**Focus:** Decentralized trading data (spot pairs, pools, liquidity, OHLCV, trades).\n\n**Tools:**\n- `DEX Metadata` – Info for any DEX (logo, date, description)  \n- `DEX Networks List` – All blockchain networks  \n- `DEX Listings Quotes` – DEXs with live trading stats  \n- `DEX Pair Quotes Latest` – Live price/liquidity for spot pairs  \n- `DEX OHLCV Historical` – Historical OHLCV (e.g., 1h, 1d)  \n- `DEX OHLCV Latest` – Real-time OHLCV for current UTC day  \n- `DEX Trades Latest` – Up to 100 recent trades  \n- `DEX Spot Pairs Latest` – All active spot pairs with filters  \n\n✅ Use for:  \n“Price history of USDT/ETH on Uniswap,” “Show DEXs with highest volume,” “Get liquidity of token pair,” “Security scan for PancakeSwap pools”\n\n---\n\n### ⚙️ Multi-Agent Coordination (Advanced Multi-Query Reasoning)\n\nYou are empowered with **advanced multi-query analysis** capabilities:\n- Chain data between agents (e.g., map → quote → historical chart)\n- Use outputs from one tool as inputs for another\n- Automatically fetch required IDs (e.g., exchange ID, contract address) before making a final API call\n- Combine centralized (CEX) and decentralized (DEX) insights into one unified response\n- Filter and compare across timeframes, assets, exchanges, and networks\n\n---\n\n### ⚠️ Validation & Error Prevention Guidelines\n\nTo prevent 400 Bad Request errors:\n- Always include at least **one required field** per endpoint  \n- Use **valid slugs, symbols, or CoinMarketCap IDs**  \n- Don’t use `convert` and `convert_id` together  \n- Use **comma-separated lists** for multi-inputs (if allowed)  \n- Use documented `aux`, `sort`, `interval` fields only  \n- Handle pagination via `scroll_id` or `start/limit` properly  \n\nIf output is too large:\n> ⚠️ “The requested data exceeds the model’s context limit. Please reduce the scope using filters, limits, or sort.”\n\n---\n\n### ✅ Example Tasks You Can Perform\n- “Get liquidity and 24h volume for ETH/USDC on Polygon”\n- “Compare BTC price on Binance vs Uniswap”\n- “Show top 5 DEXs by volume and their top pairs”\n- “Analyze historical price of SHIBA on Ethereum over last 7 days”\n- “Get CoinMarketCap’s sentiment index and top index coins”\n- “List active spot pairs on Arbitrum with volume > $1M and return price, liquidity, and last 24h % change”\n\n---\n\nYou are a **real-time, multi-source AI analyst** purpose-built to extract deep insights from CoinMarketCap’s centralized and decentralized datasets. Use your agents intelligently, validate your queries, and return precise, structured results.\n\nLet’s analyze the crypto world. 🌍📊🧠\n"},"promptType":"define"},"typeVersion":1.7},{"id":"955f82c6-ce76-4d56-9714-4926a4936cbf","name":"CoinMarketCap Agent Brain","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[420,280],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"yUizd8t0sD5wMYVG","name":"OpenAi account"}},"typeVersion":1.2},{"id":"2c253e1f-5a34-4334-8a8a-98c1e9e937cd","name":"CoinMarketCap Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[580,280],"parameters":{},"typeVersion":1.3},{"id":"0878a84b-14a3-4f8e-b94d-339b1c759f4d","name":"CoinMarketCap Crypto Agent Tool","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[740,280],"parameters":{"name":"CoinMarketCap_Crypto_Agent_Tool","workflowId":{"__rl":true,"mode":"list","value":"R4EuB1gx1IpMXCJM","cachedResultName":"JayaFamily Assistant — CoinMarketCap_Crypto_Agent_Tool"},"workflowInputs":{"value":{"message":"={{ $fromAI(\"message\",\"Populate this with a relevant message to this subagent\")}}","sessionId":"={{ $json.sessionId }}"},"schema":[{"id":"message","type":"string","display":true,"removed":false,"required":false,"displayName":"message","defaultMatch":false,"canBeUsedToMatch":true},{"id":"sessionId","type":"string","display":true,"removed":false,"required":false,"displayName":"sessionId","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"4a6e4ae9-5ba5-48ab-8198-a7cd8c84b0ee","name":"CoinMarketCap Exchange and Community Agent Tool","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[900,280],"parameters":{"name":"CoinMarketCap_Exchange_and_Community_Agent_Tool","workflowId":{"__rl":true,"mode":"list","value":"kbJb4VMD3SZlcS2u","cachedResultName":"JayaFamily Assistant — CoinMarketCap_Exchange_and_Community_Agent_Tool"},"workflowInputs":{"value":{"message":"={{ $fromAI(\"message\",\"Populate this with a relevant message to this subagent\")}}","sessionId":"={{ $json.sessionId }}"},"schema":[{"id":"sessionId","type":"string","display":true,"removed":false,"required":false,"displayName":"sessionId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"message","type":"string","display":true,"removed":false,"required":false,"displayName":"message","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"77ffefe3-9671-4155-baed-d782035b6079","name":"CoinMarketCap DEXScan Agent Tool","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[1080,280],"parameters":{"name":"CoinMarketCap_DEXScan_Agent_Tool","workflowId":{"__rl":true,"mode":"list","value":"ImiznkEUWCkKbg1w","cachedResultName":"JayaFamily Assistant — CoinMarketCap_DEXScan_Agent_Tool"},"workflowInputs":{"value":{"message":"={{ $fromAI(\"message\",\"Populate this with a relevant message to this subagent\")}}","sessionId":"={{ $json.sessionId }}"},"schema":[{"id":"sessionId","type":"string","display":true,"removed":false,"required":false,"displayName":"sessionId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"message","type":"string","display":true,"removed":false,"required":false,"displayName":"message","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"d3fc4697-478b-4e6e-8d42-8138ec614748","name":"Telegram Input","type":"n8n-nodes-base.telegramTrigger","position":[-220,0],"webhookId":"b33d2025-01c2-4386-b677-206a87a1856b","parameters":{"updates":["message"],"additionalFields":{}},"credentials":{"telegramApi":{"id":"R3vpGq0SURbvEw2Z","name":"Telegram account"}},"typeVersion":1.1},{"id":"d1108256-43c3-403f-bb7d-181c6de62f2a","name":"CMC Multi-Agent Guide","type":"n8n-nodes-base.stickyNote","position":[-1600,-1600],"parameters":{"width":1180,"height":1960,"content":"# 📊 CoinMarketCap AI Analyst Agent (n8n Workflow)\n\n## 🧠 Multi-Agent System Overview\nThis is the **primary supervisor agent** for the **CoinMarketCap AI Analyst Workflow**, designed using **modular AI agent architecture** in **n8n**.\n\n⚠️ **This workflow requires 3 external tool workflows to function properly.** You must download, install, and connect the following:\n\n### 🔌 Required Sub-Agent Tools:\n1. **CoinMarketCap_Crypto_Agent_Tool** – Handles cryptocurrency quotes, listings, conversions\n2. **CoinMarketCap_Exchange_and_Community_Agent_Tool** – Handles exchanges, trending tokens, Fear & Greed Index\n3. **CoinMarketCap_DEXScan_Agent_Tool** – Handles decentralized liquidity, pair quotes, OHLCV analysis\n\nOnce installed, these agents enable advanced capabilities:\n\n### ✅ Key AI Functions:\n- Analyze market caps, volumes, supply metrics across coins\n- Track new listings and top gainers/losers\n- Evaluate trading pairs and liquidity in CEX and DEX markets\n- Retrieve sentiment indicators and trending discussions\n\n---\n\n## 🧠 Node Structure Summary\n\n### **1️⃣ Analyst Brain**\n- **Model**: GPT-4o Mini\n- **Function**: Understands user queries, delegates tasks to agents\n\n### **2️⃣ Memory Buffer**\n- Stores session state and context between prompts\n\n### **3️⃣ Tool Triggers**\n- **toolWorkflow()** function calls: \n   - `CoinMarketCap_Crypto_Agent_Tool`\n   - `CoinMarketCap_Exchange_and_Community_Agent_Tool`\n   - `CoinMarketCap_DEXScan_Agent_Tool`\n\n---\n\n## ⚠️ Notes:\n- 📎 Make sure API credentials are installed and valid for each agent\n- 📍 Each tool runs independently but feeds results to the supervisor for synthesis\n- 🧩 Use `message` and `sessionId` parameters consistently in every sub-agent call\n\n# 📊 CoinMarketCap AI Analyst Agent Tools (n8n Workflow) Guide\n\n## 🚀 Workflow Overview\nThe **CoinMarketCap AI Analyst Agent** is a modular AI-powered system built on **n8n** to deliver **real-time crypto market insights**. It connects directly to CoinMarketCap APIs across three specialized agents:\n\n- **Cryptocurrency Agent** – Market listings, quotes, conversions, and token info.\n- **Exchange & Community Agent** – Trending topics, exchange performance, and sentiment.\n- **DEXScan Agent** – Liquidity, trading volume, and OHLC data on decentralized markets.\n\n### 🎯 **Key Capabilities**:\n- Fetch latest token listings and rank movements\n- Track real-time price quotes and convert values between currencies\n- Compare metrics like market cap, volume, and dominance\n- Monitor exchange market pairs and volume\n- Analyze community sentiment and Fear & Greed Index\n- Visualize DEX liquidity and historical trading trends\n\n---\n\n## 🔗 Node Architecture Summary\n\n### **1️⃣ AI Analyst Brain**\n- **Type**: GPT-4o Mini\n- **Function**: Interprets prompts and queries, routes requests to proper sub-agent.\n\n### **2️⃣ Session Memory**\n- **Type**: Memory Buffer\n- **Function**: Maintains query context during conversation.\n\n### **3️⃣ Tool Agents**\n- **Type**: Tool Workflow\n- Cryptocurrency / Exchange / DEXScan agent endpoints trigger APIs with mapped params.\n\n"},"typeVersion":1},{"id":"5800cdc3-7d4b-4385-8401-b5913a43a28d","name":"CMC Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[1260,-1600],"parameters":{"color":3,"width":680,"height":600,"content":"## ⚠️ Error Handling Guide\n\n| **Error Code** | **Meaning** |\n|---------------|------------|\n| `200` | Success |\n| `400` | Bad Request (invalid query/params) |\n| `401` | Unauthorized (missing or invalid API key) |\n| `429` | Rate Limit Exceeded |\n| `500` | CoinMarketCap server error |\n\n### 🔍 Common Fixes\n- Ensure `symbol`, `slug`, or `id` match valid CoinMarketCap entries\n- Use correct `timestamp`, `network`, and pagination parameters\n- Rate-limit high-frequency queries to avoid 429 errors\n\n---\n\n## 🚀 Need Help?\nFor custom CoinMarketCap agent support, dashboards, or token data automation, connect:\n\n🌐 **Don Jayamaha — LinkedIn**  \n🔗 [http://linkedin.com/in/donjayamahajr](http://linkedin.com/in/donjayamahajr)\n\n© 2025 Treasurium Capital Limited Company. All rights reserved.\nThis AI workflow architecture, including logic, design, and prompt structures, is the intellectual property of Treasurium Capital Limited Company. Unauthorized reproduction, redistribution, or resale is prohibited under U.S. copyright law. Licensed use only.\n"},"typeVersion":1},{"id":"068e7732-d92e-4a1d-a4b5-c0ee6363f3fb","name":"CMC Sticky Note","type":"n8n-nodes-base.stickyNote","position":[0,-1600],"parameters":{"color":5,"width":900,"height":1500,"content":"## 📌 How to Use the Workflow\n\n### ✅ Step 1: Provide Inputs\n- Use token `symbol`, `slug`, or `ID`\n- Set timestamps (`before`, `after`) in **Unix format** for historical data\n- Use `chain`, `limit`, and `start` for pagination when needed\n\n### ✅ Step 2: Execute API Tools\n- The AI routes queries to sub-agents: **Cryptocurrency**, **Exchange**, or **DEXScan**\n\n### ✅ Step 3: Get Response & Output\n- Results can be output to Telegram, dashboards, or n8n HTTP Response nodes\n\n---\n\n## 🗣️ Example Questions to Ask the CMC AI Analyst\n\n### 💬 Market Intelligence\n- \"What are the top 5 tokens by trading volume right now?\"\n- \"Which coins gained the most in the last 24 hours?\"\n- \"What’s the total crypto market cap today?\"\n\n### 💬 Token Insights\n- \"What’s the price of SOL in USD?\"\n- \"How much is 1000 USDT in BTC?\"\n- \"Show me the description and whitepaper link for Dogecoin.\"\n\n### 💬 Exchange & Sentiment\n- \"What’s the Fear & Greed index today?\"\n- \"List exchanges with the highest asset holdings.\"\n- \"Give me info about Binance – when was it launched?\"\n\n### 💬 DEX Data\n- \"Show me the top DEX spot pairs on Ethereum.\"\n- \"What’s the OHLCV data for SOL-USDT on Solana over the last 7 days?\"\n- \"What trades just occurred on PancakeSwap?\"\n\n---\n\n## ⚠️ Example API Queries\n\n### 1️⃣ Get Top 5 Tokens by Volume\n```plaintext\nGET /v1/cryptocurrency/listings/latest?sort=volume_24h&limit=5\n```\n\n### 2️⃣ Convert 1000 USDT to BTC\n```plaintext\nGET /v1/tools/price-conversion?amount=1000&symbol=USDT&convert=BTC\n```\n\n### 3️⃣ Check Fear & Greed Index\n```plaintext\nGET /v3/fear-and-greed/latest\n```\n\n### 4️⃣ Get OHLCV of DEX Pair\n```plaintext\nGET /v4/dex/pairs/ohlcv/historical?network=solana&pair=SOL-USDT&interval=1d\n```\n\n---"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"ed2f29c5-293a-4796-8986-9c5f9980c6c6","connections":{"Adds SessionId":{"main":[[{"node":"CoinMarketCap AI Data Analyst Agent","type":"main","index":0}]]},"Telegram Input":{"main":[[{"node":"Adds SessionId","type":"main","index":0}]]},"CoinMarketCap Memory":{"ai_memory":[[{"node":"CoinMarketCap AI Data Analyst Agent","type":"ai_memory","index":0}]]},"CoinMarketCap Agent Brain":{"ai_languageModel":[[{"node":"CoinMarketCap AI Data Analyst Agent","type":"ai_languageModel","index":0}]]},"CoinMarketCap Crypto Agent Tool":{"ai_tool":[[{"node":"CoinMarketCap AI Data Analyst Agent","type":"ai_tool","index":0}]]},"CoinMarketCap DEXScan Agent Tool":{"ai_tool":[[{"node":"CoinMarketCap AI Data Analyst Agent","type":"ai_tool","index":0}]]},"CoinMarketCap AI Data Analyst Agent":{"main":[[{"node":"Telegram Send Message","type":"main","index":0}]]},"CoinMarketCap Exchange and Community Agent Tool":{"ai_tool":[[{"node":"CoinMarketCap AI Data Analyst Agent","type":"ai_tool","index":0}]]}}}


name: Automate Call Scheduling with Voice AI Receptionist using Vapi, Google Calendar & Airtable
author_name: SuperAgent
author_username: customaistudio
nodes_used: ["n8n-nodes-base.airtable","n8n-nodes-base.googleCalendar","n8n-nodes-base.code"]
categories: []
created_at: 2025-04-03T19:05:21.114Z
updated_at: 2025-04-03T19:05:21.114Z
url: https://n8n.io/workflows/3427
scraped_at: 2025-06-19 22:49:05
description:
  Who is this template for?

  This template is ideal for small businesses, agencies, and solo professionals who want to automate appointment scheduling and caller follow-up through a voice-based AI receptionist. If you’re using tools like Google Calendar, Airtable, and Vapi (Twilio), this setup is for you.

  What problem does this workflow solve?

  Manual call handling, appointment booking, and email coordination can be time-consuming and prone to errors. This workflow solves that by automating the receptionist role: answering calls, checking calendar availability, managing appointments, and storing call summaries—all without human intervention.

  What this workflow does

  This Agent Receptionist manages inbound voice calls and scheduling tasks using Vapi and Google Calendar. It checks availability, books or updates calendar events, sends email confirmations, and logs call details into Airtable. The workflow includes built-in logic for slot management, email triggers, and storing call transcripts. 

  Setup Instructions

  Duplicate Airtable Base: Use this Airtable base templateBASE LINK 

  Import Workflow: Load provided JSON into your n8n instance.

  Credentials: Connect your Google Calendar and Airtable credentials in n8n.

  Activate Workflow: Enable workflow to get live webhook URLs.

  Vapi Configuration:

  Paste provided system prompt into Vapi Assistant. 

  Link the appropriate webhook URLs from n8n (GetSlots, BookSlots, UpdateSlots, CancelSlots, and end-of-call report).



  Disclaimer

  Optimized for cloud-hosted n8n instances. Self-hosted users should verify webhook and credential setups.

workflow_json:
  {"meta":{"instanceId":"1954c8c806bedb8f0628725b26b786028ade16c78a82bc25deb9dd961e036832"},"nodes":[{"id":"36d0b0d4-b454-4a9b-8168-bcc7942a7cc7","name":"Input Arguments","type":"n8n-nodes-base.set","position":[520,740],"parameters":{"options":{},"assignments":{"assignments":[{"id":"ccabe9f4-7911-4488-a75b-7c5779fb2014","name":"timeZone","type":"string","value":"=America/Chicago"},{"id":"b802d976-78f5-4c00-8764-f8c49eaded29","name":"endtime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.endtime }}"},{"id":"02d58122-6a0f-4bdb-9914-6f50d2af6df4","name":"starttime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.starttime }}"},{"id":"c1249493-a1d7-4a91-9468-9e5c49430d2e","name":"body.message.toolCalls[0].id","type":"string","value":"={{ $json.body.message.toolCalls[0].id }}"},{"id":"2d1e0d9a-4c70-488e-b430-b8137fd54970","name":"customer.number","type":"string","value":"={{ $json.body.message.call.customer.number }}"}]}},"typeVersion":3.3},{"id":"2d8485ad-9007-4664-9182-7eda25fc96ee","name":"Format response","type":"n8n-nodes-base.itemLists","position":[2000,840],"parameters":{"include":"allFieldsExcept","options":{},"aggregate":"aggregateAllItemData","operation":"concatenateItems","fieldsToExclude":"sort","destinationFieldName":"response"},"typeVersion":3},{"id":"b23c75e0-3697-4137-a595-cf26fedaa898","name":"Sort","type":"n8n-nodes-base.itemLists","position":[1760,840],"parameters":{"options":{},"operation":"sort","sortFieldsUi":{"sortField":[{"fieldName":"sort"}]}},"typeVersion":3},{"id":"660e3d2f-a424-4e76-8c13-5b62b9f22202","name":"Available Start Times & Ranges","type":"n8n-nodes-base.code","position":[2240,840],"parameters":{"jsCode":"// Input data\nconst inputData = $input.all()[0].json.response;\n\n// Define workday hours in CST\nconst WORKDAY_START = \"09:00:00 CST\";\nconst WORKDAY_END = \"18:00:00 CST\";\nconst SLOT_DURATION = 30 * 60 * 1000; // 30 minutes in milliseconds\n\n// Helper to parse CST datetime strings\nconst parseCST = (datetime) => {\n  const parsedDate = new Date(datetime.replace(\" CST\", \"-06:00\"));\n  return isNaN(parsedDate) ? null : parsedDate;\n};\n\n// Function to generate 30-minute start times\nconst generateStartTimes = (start, end) => {\n  const startTimes = [];\n  let current = new Date(start);\n\n  while (current < end) {\n    startTimes.push(\n      current.toLocaleTimeString('en-US', {\n        timeZone: 'CST',\n        hour: '2-digit',\n        minute: '2-digit',\n      })\n    );\n    current = new Date(current.getTime() + SLOT_DURATION);\n  }\n\n  return startTimes;\n};\n\n// Function to find wide open ranges\nconst findWideOpenRanges = (startTimes) => {\n  if (startTimes.length < 3) return []; // Not enough slots for a wide open range\n\n  const ranges = [];\n  let rangeStart = null;\n  let consecutiveCount = 0;\n\n  for (let i = 0; i < startTimes.length - 1; i++) {\n    const currentTime = parseCST(`2000-01-01 ${startTimes[i]} CST`);\n    const nextTime = parseCST(`2000-01-01 ${startTimes[i + 1]} CST`);\n    const diff = nextTime - currentTime;\n\n    if (diff === SLOT_DURATION) {\n      consecutiveCount += 1;\n      if (rangeStart === null) rangeStart = startTimes[i];\n    } else {\n      if (consecutiveCount >= 2) {\n        ranges.push(`${rangeStart} to ${startTimes[i]}`);\n      }\n      rangeStart = null;\n      consecutiveCount = 0;\n    }\n  }\n\n  // Handle the final range\n  if (consecutiveCount >= 2) {\n    ranges.push(`${rangeStart} to ${startTimes[startTimes.length - 1]}`);\n  }\n\n  return ranges;\n};\n\n// Group meetings by date, ignoring invalid dates\nconst meetingsByDate = inputData.reduce((acc, meeting) => {\n  const start = parseCST(meeting.start);\n  const end = parseCST(meeting.end);\n\n  if (!start || !end) {\n    return acc; // Ignore invalid dates\n  }\n\n  const dateKey = start.toISOString().split('T')[0];\n\n  if (!acc[dateKey]) {\n    acc[dateKey] = [];\n  }\n\n  acc[dateKey].push({ start, end });\n  return acc;\n}, {});\n\n// Generate availability\nconst availability = Object.keys(meetingsByDate)\n  .filter((date) => {\n    // Exclude Saturdays (6) and Sundays (0)\n    const dayOfWeek = new Date(date).getUTCDay();\n    return dayOfWeek !== 0 && dayOfWeek !== 6;\n  })\n  .map((date) => {\n    const workdayStart = parseCST(`${date} ${WORKDAY_START}`);\n    const workdayEnd = parseCST(`${date} ${WORKDAY_END}`);\n\n    const dayMeetings = meetingsByDate[date].sort((a, b) => a.start - b.start);\n\n    let availableStartTimes = [];\n    let lastEnd = workdayStart;\n\n    for (const meeting of dayMeetings) {\n      if (meeting.start > lastEnd) {\n        availableStartTimes = availableStartTimes.concat(generateStartTimes(lastEnd, meeting.start));\n      }\n      lastEnd = meeting.end > lastEnd ? meeting.end : lastEnd;\n    }\n\n    if (lastEnd < workdayEnd) {\n      availableStartTimes = availableStartTimes.concat(generateStartTimes(lastEnd, workdayEnd));\n    }\n\n    const wideOpenRanges = findWideOpenRanges(availableStartTimes);\n\n    return {\n      date: new Date(date).toLocaleDateString('en-US', {\n        weekday: 'long',\n        year: 'numeric',\n        month: 'long',\n        day: 'numeric',\n      }),\n      availableStartTimes,\n      wideOpenRanges,\n    };\n  });\n\n// Format output as plaintext\nconst availableTimes = availability\n  .map(({ date, availableStartTimes, wideOpenRanges }) => {\n    const times = availableStartTimes.map((time) => `- ${time}`).join('\\n');\n    const ranges = wideOpenRanges.length\n      ? `Wide Open Ranges:\\n${wideOpenRanges.map((range) => `- ${range}`).join('\\n')}`\n      : \"Wide Open Ranges: None\";\n\n    return `### ${date}\\nAvailable Start Times:\\n${times}\\n\\n${ranges}`;\n  })\n  .join('\\n\\n');\n\n// Set the output\nreturn {\n  json: {\n    availableTimes,\n  },\n};\n"},"typeVersion":2},{"id":"f3110658-2f90-4b19-9874-7d6c4e108895","name":"Flatten Slots","type":"n8n-nodes-base.code","position":[2460,840],"parameters":{"mode":"runOnceForEachItem","jsCode":"const flattenSlots = (data) => {\n  // If data is missing or empty, return an empty array of slots\n  if (!data) {\n    return { slots: [] };\n  }\n\n  // data is an object whose keys are dates\n  // each date key has an array of slot objects\n  // we just need to flatten them all into one array\n  const flattened = Object.values(data).flat();  // merges all arrays from each date key\n\n  // Return a new object with a single 'slots' array\n  return { slots: flattened };\n};\n\n// Then assign the flattened slots back to $input.item.json.data\n$input.item.json.data = flattenSlots($input.item.json.data);\nreturn $input.item;\n"},"typeVersion":2},{"id":"5065439e-34e3-4eaf-8226-8ba7393a5cf3","name":"Enrich Date","type":"n8n-nodes-base.code","position":[2680,840],"parameters":{"mode":"runOnceForEachItem","jsCode":"function formatTimeSlot(dateString) {\n  // Format options for date/time with America/Chicago timezone\n  const options = {\n    timeZone: 'America/Chicago',\n    weekday: 'long',\n    month: 'long',\n    day: 'numeric',\n    hour: 'numeric',\n    minute: 'numeric',\n    hour12: true\n  };\n\n  // Create a formatter with timezone support\n  const dateFormatter = new Intl.DateTimeFormat('en-US', options);\n  \n  // Format the date/time string\n  return dateFormatter.format(new Date(dateString));\n}\n\n// Process each slot and add formatted time strings to the result\nconst slots = $input.item.json.data.slots;\nconst formattedSlots = slots.map(slot => formatTimeSlot(slot.start));\n\n// Attach formatted results to the output\n$input.item.json.data.slots = formattedSlots;\n\nreturn $input.item;\n"},"typeVersion":2},{"id":"d8ed3a92-697b-4718-b65f-5276c9a9bfaf","name":"Build Response Payload","type":"n8n-nodes-base.set","position":[2900,840],"parameters":{"options":{},"assignments":{"assignments":[{"id":"5cb05b10-e916-459e-84a2-9c314a859a07","name":"results[0].toolCallId","type":"string","value":"={{ $('Input Arguments').item.json.body.message.toolCalls[0].id }}"},{"id":"552246f9-7afd-404e-9fb3-cb38c7447359","name":"results[0].result","type":"string","value":"={{ $json.availableTimes }}"}]}},"typeVersion":3.4},{"id":"a0697944-c5a6-4ca1-9948-8248940841b2","name":"Booking Payload","type":"n8n-nodes-base.set","position":[1980,1400],"parameters":{"options":{"ignoreConversionErrors":true},"assignments":{"assignments":[{"id":"05bbc797-b781-489c-ab70-e234fe17eb62","name":"id","type":"number","value":"={{ $json.id }}"},{"id":"4bb68abf-18c8-4445-b446-21667abd95aa","name":"description","type":"string","value":"={{ $json.description }}"},{"id":"74a98b77-b9fe-40cc-84c8-fc7303c5cfa6","name":"startTime","type":"string","value":"={{ $json.start.dateTime }}"},{"id":"2934d6a7-9e6b-4038-891c-0b05ba18cb21","name":"endTime","type":"string","value":"={{ $json.end.dateTime }}"},{"id":"10f091c8-5e52-40dc-a294-87625be9af99","name":"status","type":"string","value":"={{ $json.status }}"},{"id":"cdc5e1ab-a29b-447f-8343-ff1c1b168717","name":"Timezone","type":"string","value":"={{ $json.end.timeZone }}"},{"id":"f5b6820c-ab4b-496c-9957-f86753243388","name":"attendees","type":"array","value":"={{ $json.attendees }}"},{"id":"b39a06a5-4fbf-4fdf-9d9a-a07dcb37d157","name":"hangoutLink","type":"string","value":"={{ $json.hangoutLink }}"},{"id":"345f49fc-93bc-48b8-9ced-326139a82119","name":"Title","type":"string","value":"={{ $json.summary }}"}]}},"typeVersion":3.4},{"id":"4f7b157c-f657-48fa-8bb5-a1e074b042eb","name":"Success Response","type":"n8n-nodes-base.set","position":[2200,1400],"parameters":{"options":{},"assignments":{"assignments":[{"id":"2c3894da-7bf7-4a35-95c0-d3d9199dd0ad","name":"results[0].toolCallId","type":"string","value":"={{ $('Input Arguments from booking tools').item.json.toolCallId }}"},{"id":"685c67c7-a30b-4bcc-b9ba-827c4b570548","name":"results[0].result","type":"string","value":"={{ $json.status }}"}]}},"typeVersion":3.3},{"id":"b7fe16e3-b625-4cb4-b971-9c26698af89b","name":"Add Friendly Error","type":"n8n-nodes-base.code","position":[1980,1760],"parameters":{"mode":"runOnceForEachItem","jsCode":"function replaceValue(value) {\n  if (error.message.include('no_available_users_found_error')) {\n    return \"This time slot is no longer available.\";\n  }\n  return value;\n}\n\n$input.item.json.message = replaceValue($input.item.json.error.description);\n\nreturn $input.item;"},"typeVersion":2},{"id":"b5bff0df-2bef-4c43-9fcf-91cadc68b7ca","name":"Error Response","type":"n8n-nodes-base.set","position":[2200,1760],"parameters":{"options":{},"assignments":{"assignments":[{"id":"2c3894da-7bf7-4a35-95c0-d3d9199dd0ad","name":"results[0].toolCallId","type":"string","value":"={{ $('Input Arguments from booking tools').item.json.toolCallId }}"},{"id":"93e45166-de94-4fa5-9148-2b8d0e4b960c","name":"results[0].result","type":"string","value":"={{ $json.message || $json.status }}"}]}},"typeVersion":3.3},{"id":"fe62c0bc-2d73-4f14-8e76-02847ef4e14a","name":"Escape Json","type":"n8n-nodes-base.code","position":[1260,1580],"parameters":{"mode":"runOnceForEachItem","jsCode":"const escapeStringForJson = (str) => {\n    return str\n        .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n        .replace(/\"/g, '\\\\\"')    // Escape double quotes\n        .replace(/\\n/g, '\\\\n')   // Escape newlines\n        .replace(/\\r/g, '\\\\r')   // Escape carriage returns\n        .replace(/\\t/g, '\\\\t');  // Escape tabs\n};\n\n// Escape the notes field\n$input.item.json.notes = escapeStringForJson($input.item.json.notes);\n\nreturn $input.item;\n"},"typeVersion":2},{"id":"17927aa4-8f91-4134-b914-1160a724226f","name":"Has all information","type":"n8n-nodes-base.if","position":[940,1800],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"e0af7f69-0c89-4a02-a49f-dd5a90e31dff","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{ ($json.email || \"\").isEmail() }}","rightValue":""}]}},"typeVersion":2.2},{"id":"6f0bb9e6-9d82-4cc6-a98f-4d00c47ed910","name":"Respond with Error","type":"n8n-nodes-base.respondToWebhook","position":[1480,1900],"parameters":{"options":{}},"typeVersion":1.1},{"id":"fdedba34-a374-405d-a86e-0b0a1759ede9","name":"Build Error Response Payload","type":"n8n-nodes-base.set","position":[1260,1900],"parameters":{"options":{},"assignments":{"assignments":[{"id":"5cb05b10-e916-459e-84a2-9c314a859a07","name":"results[0].toolCallId","type":"string","value":"={{ $('Input Arguments from booking tools').item.json.toolCallId }}"},{"id":"552246f9-7afd-404e-9fb3-cb38c7447359","name":"results[0].result","type":"string","value":"=You must provide an email, name and notes to call this tool"}]}},"typeVersion":3.4},{"id":"1e111f9d-bb43-4126-b7a2-3353e7c7c72f","name":"Build Error Response Payload2","type":"n8n-nodes-base.set","position":[1560,2840],"parameters":{"options":{},"assignments":{"assignments":[{"id":"5cb05b10-e916-459e-84a2-9c314a859a07","name":"results[0].toolCallId","type":"string","value":"={{ $('Input Arguments from updateslot tool').item.json.toolCallId || $json.Calls[0].id }}"},{"id":"552246f9-7afd-404e-9fb3-cb38c7447359","name":"results[0].result","type":"string","value":"=You must provide an email, name , previous starttime & endtime and resceduled starttime to call this tool"}]}},"typeVersion":3.4},{"id":"d6cbad26-d974-4a11-b0fd-2a35bb555378","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[260,620],"parameters":{"color":4,"width":190,"height":80,"content":"# Get Slots"},"typeVersion":1},{"id":"bcccc8cb-2e9d-4f8b-9964-e4d656e794ed","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[740,920],"parameters":{"width":230,"height":80,"content":"## Check Availability\n"},"typeVersion":1},{"id":"30b34e37-ee7a-434c-ab4d-445df994459a","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[1320,520],"parameters":{"width":310,"height":80,"content":"## If time available Respond\n"},"typeVersion":1},{"id":"725a9b59-ea66-4326-a410-93a723157ced","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1280,1020],"parameters":{"width":190,"height":80,"content":"## Get All Events\n"},"typeVersion":1},{"id":"1f2bf4a3-8aeb-4a56-8bff-0bb370e12718","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[2140,1020],"parameters":{"width":350,"height":100,"content":"## Get Available Slots\n\nFormat the slots and Enrich the date and timings\n"},"typeVersion":1},{"id":"5909d88f-b9c6-4e62-b1e3-bdc1d05ad7aa","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[3280,1000],"parameters":{"width":230,"height":80,"content":"## Respond to Vapi"},"typeVersion":1},{"id":"f627c5b0-f3b6-4f95-a3a3-2c1b7e2860c7","name":"Sticky Note BookSlot Webhook","type":"n8n-nodes-base.stickyNote","position":[380,1680],"parameters":{"color":5,"width":190,"height":80,"content":"# Book Slot"},"typeVersion":1},{"id":"9c3e8b9f-3fe3-4380-8cbc-413146d752b9","name":"Sticky Note BookSlot Check","type":"n8n-nodes-base.stickyNote","position":[880,1700],"parameters":{"width":230,"height":80,"content":"Checks if required booking info (email, name, etc.) is provided."},"typeVersion":1},{"id":"c723bbd0-5a04-4efb-ba67-59bc722b9d4e","name":"Sticky Note BookSlot Error","type":"n8n-nodes-base.stickyNote","position":[1440,2060],"parameters":{"width":190,"height":80,"content":"If info missing, sends error back."},"typeVersion":1},{"id":"a843e795-8046-4538-93e0-2de2e688c863","name":"Sticky Note BookSlot GCal","type":"n8n-nodes-base.stickyNote","position":[1660,1740],"parameters":{"width":190,"height":80,"content":"Books the appointment in Google Calendar."},"typeVersion":1},{"id":"a7627281-15fc-438a-b031-b00cbc4b9fa4","name":"Sticky Note BookSlot Error Handle","type":"n8n-nodes-base.stickyNote","position":[1920,1920],"parameters":{"width":230,"height":80,"content":"Handles potential booking errors (e.g., slot taken)."},"typeVersion":1},{"id":"71c0c722-b5df-47d7-97e6-3d23533a4a4e","name":"Sticky Note BookSlot Response","type":"n8n-nodes-base.stickyNote","position":[2420,1740],"parameters":{"width":210,"height":80,"content":"Sends confirmation/error back to Vapi."},"typeVersion":1},{"id":"4e598ebb-cfdb-432f-a01a-bb76d1d20f24","name":"Sticky Note BookSlot Airtable","type":"n8n-nodes-base.stickyNote","position":[3100,1740],"parameters":{"width":230,"height":80,"content":"Logs the confirmed booking details to Airtable."},"typeVersion":1},{"id":"cc085c75-d45f-4453-b78b-1b9b480fb02c","name":"Sticky Note CancelSlot Webhook","type":"n8n-nodes-base.stickyNote","position":[440,3480],"parameters":{"color":3,"width":250,"height":80,"content":"# Cancel Slots"},"typeVersion":1},{"id":"9504b7e8-7964-4a0e-bfa4-32540c1fb895","name":"Sticky Note CancelSlot Check","type":"n8n-nodes-base.stickyNote","position":[960,3780],"parameters":{"width":230,"height":80,"content":"Checks if required info (email, name, start time) is provided."},"typeVersion":1},{"id":"3bb9d976-d922-4016-839c-22e8b1adcf35","name":"Sticky Note CancelSlot Error","type":"n8n-nodes-base.stickyNote","position":[1520,3940],"parameters":{"width":150,"height":80,"content":"If info missing, sends error back."},"typeVersion":1},{"id":"87442b3a-b8eb-43e6-b15d-0240a58bff79","name":"Sticky Note CancelSlot Search","type":"n8n-nodes-base.stickyNote","position":[1300,3440],"parameters":{"width":190,"height":100,"content":"Finds the appointment record in Airtable by phone number to get event ID."},"typeVersion":1},{"id":"4e0cec59-1acc-4604-80ce-09479c7a6652","name":"Sticky Note CancelSlot GCal Delete","type":"n8n-nodes-base.stickyNote","position":[1720,3720],"parameters":{"width":190,"height":80,"content":"Deletes the event from Google Calendar using event ID."},"typeVersion":1},{"id":"68e00556-93d2-45a8-9fee-deb1477ffff2","name":"Sticky Note CancelSlot Airtable Update","type":"n8n-nodes-base.stickyNote","position":[2060,3400],"parameters":{"width":190,"height":80,"content":"Updates Airtable record status to 'Canceled'."},"typeVersion":1},{"id":"5853b0f6-1e73-435e-aff8-5d9d8de53693","name":"Sticky Note CancelSlot Response","type":"n8n-nodes-base.stickyNote","position":[2380,3740],"parameters":{"width":190,"height":80,"content":"Sends cancellation confirmation/error back to Vapi."},"typeVersion":1},{"id":"660cdb51-84ac-434e-b7d8-f7b17ef7ef5b","name":"Sticky Note UpdateSlot Webhook","type":"n8n-nodes-base.stickyNote","position":[460,2600],"parameters":{"color":6,"width":250,"height":80,"content":"# Update Slots"},"typeVersion":1},{"id":"030e4bce-4b8b-42b7-8cf4-86b3a88f375b","name":"Sticky Note UpdateSlot Check","type":"n8n-nodes-base.stickyNote","position":[1000,2900],"parameters":{"width":230,"height":80,"content":"Checks if required info (email, name, old/new times) is provided."},"typeVersion":1},{"id":"02e9f8e3-7561-4ace-95a2-2b1807940f1a","name":"Sticky Note UpdateSlot Error","type":"n8n-nodes-base.stickyNote","position":[1500,3020],"parameters":{"width":190,"height":80,"content":"If info missing, sends error back."},"typeVersion":1},{"id":"4820cb6c-de15-4e9a-bca7-e3f172af6b80","name":"Sticky Note UpdateSlot Search","type":"n8n-nodes-base.stickyNote","position":[1580,2460],"parameters":{"width":190,"height":80,"content":"Finds original appointment in Airtable by old phone number"},"typeVersion":1},{"id":"5dd3075e-8e0b-4f76-8d21-39aa66d449da","name":"Sticky Note UpdateSlot GCal Update","type":"n8n-nodes-base.stickyNote","position":[1940,2720],"parameters":{"width":190,"height":80,"content":"Updates the event time in Google Calendar."},"typeVersion":1},{"id":"2e08b4f6-f279-4a9e-9bd3-d6a6283b45f4","name":"Sticky Note UpdateSlot Airtable Update","type":"n8n-nodes-base.stickyNote","position":[2240,2320],"parameters":{"width":170,"height":100,"content":"Updates Airtable record with new times & 'Updated' status."},"typeVersion":1},{"id":"d1369c19-401e-4ce2-a21e-0d5ae01af119","name":"Sticky Note UpdateSlot Response","type":"n8n-nodes-base.stickyNote","position":[2720,2460],"parameters":{"width":230,"height":80,"content":"Sends rescheduling confirmation/error back to Vapi."},"typeVersion":1},{"id":"ca064fbe-b175-443f-b8e8-70a2a7551ba9","name":"Sticky Note CallResults Webhook","type":"n8n-nodes-base.stickyNote","position":[440,4160],"parameters":{"color":2,"width":390,"height":120,"content":"# Call Result logs\nReceives call summary and recording details post-call."},"typeVersion":1},{"id":"4941246b-82d1-4f16-b7b8-e1fdb6e7c833","name":"Sticky Note CallResults Airtable","type":"n8n-nodes-base.stickyNote","position":[860,4460],"parameters":{"width":230,"height":80,"content":"Logs call transcript, recording URL, summary, cost, customer number to Airtable."},"typeVersion":1},{"id":"e5622e9e-9b0a-43b2-ab80-e3e33a4b0409","name":"Getslot_tool","type":"n8n-nodes-base.webhook","position":[260,740],"webhookId":"42afdbc1-afd0-4d65-a713-cf7a59062d6c","parameters":{"path":"getslots","options":{},"httpMethod":"POST","responseMode":"responseNode"},"typeVersion":2},{"id":"e15781cf-5405-4f60-aa6d-ba19d1b7dabc","name":"Check Availability","type":"n8n-nodes-base.googleCalendar","position":[800,740],"parameters":{"options":{},"timeMax":"={{ $json.endtime.toDateTime() || $now.plus(1, 'hour').toISO() }}","timeMin":"={{ $json.starttime.toDateTime() }}","calendar":{"__rl":true,"mode":"list","value":"pratik@customaistudio.io","cachedResultName":"pratik@customaistudio.io"},"resource":"calendar"},"credentials":{},"typeVersion":1.3},{"id":"1e064283-2964-4eba-a893-e4270157c603","name":"Response","type":"n8n-nodes-base.respondToWebhook","position":[1540,640],"parameters":{"options":{},"respondWith":"json","responseBody":"={\n    \"results\":[\n        {\n            \"toolCallId\":\"{{ $('Getslot_tool').first().json.body.message.toolCalls[0].id }}\",\n            \"result\":\"available:{{ $json.available }}\"\n        }\n    ]\n}"},"typeVersion":1.1},{"id":"498401cb-00e5-4fdd-b6a9-dd3e91376993","name":"Check if time is available or not","type":"n8n-nodes-base.if","position":[1020,740],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"4a8741a2-a903-4fb7-b0a3-5c74c7eea6ca","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{ $json.available }}","rightValue":"="}]}},"typeVersion":2.2},{"id":"96e43c15-a332-4acf-af04-80dd989d5660","name":"Time available (true) & Call_id","type":"n8n-nodes-base.set","position":[1320,640],"parameters":{"options":{},"assignments":{"assignments":[{"id":"f582d965-af15-4ecf-8a8c-d8bf6c0d15c1","name":"body.message.toolCalls[0].id","type":"string","value":"={{ $('Input Arguments').item.json.body.message.toolCalls[0].id }}"},{"id":"834ee925-5c8d-4e46-aeee-f399dc1ff40c","name":"available","type":"boolean","value":"={{ $json.available }}"}]}},"typeVersion":3.4},{"id":"fb7ad8c6-9f78-4518-b955-60f3f7088cb9","name":"Get All Calendar Events","type":"n8n-nodes-base.googleCalendar","position":[1320,840],"parameters":{"options":{"orderBy":"startTime","timeMax":"={{ $now.plus(1, 'week').toISO() }}","timeMin":"={{ $now.toISO() }}","singleEvents":true},"calendar":{"__rl":true,"mode":"list","value":"pratik@customaistudio.io","cachedResultName":"pratik@customaistudio.io"},"operation":"getAll","returnAll":true},"credentials":{},"typeVersion":1,"alwaysOutputData":true},{"id":"390599ee-ddeb-4628-af0b-36fbdd357cee","name":"Extract start, end and name","type":"n8n-nodes-base.set","position":[1540,840],"parameters":{"options":{"ignoreConversionErrors":true},"assignments":{"assignments":[{"id":"1045b97f-c76f-450e-8f57-008602000848","name":"start","type":"string","value":"={{ DateTime.fromISO($json.start.dateTime).toLocaleString(DateTime.DATE_HUGE) }}, {{ DateTime.fromISO($json.start.dateTime).toLocaleString(DateTime.TIME_24_WITH_SHORT_OFFSET) }}"},{"id":"457e3a2b-d33e-4a65-b2da-d19ad9d754ac","name":"end","type":"string","value":"={{ DateTime.fromISO($json.end.dateTime).toLocaleString(DateTime.DATE_HUGE) }}, {{ DateTime.fromISO($json.end.dateTime).toLocaleString(DateTime.TIME_24_WITH_SHORT_OFFSET) }}"},{"id":"b6802452-557e-4568-af14-4574e8ecc013","name":"name","type":"string","value":"={{ $json.summary }}"},{"id":"799b656f-68b6-467c-88a1-217ff7c7801b","name":"sort","type":"string","value":"={{ $json.start.dateTime }}"}]}},"typeVersion":3.4},{"id":"2c9a73da-37b7-4abd-af5e-695036cd2c2b","name":"Convert into Json format for Vapi","type":"n8n-nodes-base.code","position":[3120,840],"parameters":{"jsCode":"// Get the input data for the first item\nconst inputData = $input.first().json;\nconsole.log(\"Input Data:\", inputData); // Log input for debugging\n\n// Access the message string from the correct path within the input structure.\n// The input comes from the \"Build Response Payload\" node, which structures data under 'results'.\n// Use optional chaining (?.) for safety in case the structure is not as expected.\nlet message = inputData.results?.[0]?.result;\n\n// Check if the message was found and is a string\nif (typeof message !== 'string') {\n    console.error(\"Could not find the message string at inputData.results[0].result or it's not a string. Input:\", inputData);\n    // Return an object with an empty message or an error indicator\n    return { message: \"\" }; // Or potentially throw an error: throw new Error(\"Input message not found or not a string\");\n}\n\n// Start cleaning the message string\n\n// 1. Replace the literal string \"\\\\n\" (backslash followed by n) with a space.\n// This handles the newline representation seen in the input screenshot.\nlet cleanedMessage = message.replace(/\\\\n/g, ' ');\n\n// 2. Remove spaces immediately surrounding colons (e.g., \"Times : \" becomes \"Times:\").\ncleanedMessage = cleanedMessage.replace(/\\s*:\\s*/g, ':');\n\n// 3. Replace sequences of multiple whitespace characters (including spaces from replaced \\n)\n// with a single space. Then, trim any leading or trailing whitespace from the result.\ncleanedMessage = cleanedMessage.replace(/\\s+/g, ' ').trim();\n\n// Create the final output JSON object containing the cleaned message.\nconst output = {\n    message: cleanedMessage\n};\n\n// Return the output object. This will be the output of the Code node.\nreturn output;"},"typeVersion":2},{"id":"e00cf72a-af6a-441b-9b76-81bd8096d3df","name":"Response to Vapi","type":"n8n-nodes-base.respondToWebhook","position":[3360,840],"parameters":{"options":{},"respondWith":"json","responseBody":"={\n    \"results\":[\n        {\n            \"toolCallId\":\"{{ $('Getslot_tool').first().json.body.message.toolCalls[0].id }}\",\n            \"result\":\"The original time is not available, here are available slots:{{ $json.message }}\"\n        }\n    ]\n}"},"typeVersion":1.1},{"id":"facf3bf9-e05e-4953-a221-bf7f566a3b0f","name":"bookslots_tool","type":"n8n-nodes-base.webhook","position":[400,1800],"webhookId":"42afdbc1-afd0-4d65-a713-cf7a59062d6c","parameters":{"path":"bookslots","options":{},"httpMethod":"POST","responseMode":"responseNode"},"typeVersion":2},{"id":"9266904b-300f-4c83-a518-4cd69b13de41","name":"Input Arguments from booking tools","type":"n8n-nodes-base.set","position":[720,1800],"parameters":{"options":{},"assignments":{"assignments":[{"id":"eac930a3-ba65-4b0d-b236-aa167d7edb3f","name":"toolCallId","type":"string","value":"={{ $json.body.message.toolCalls[0].id }}"},{"id":"492186b8-e3a3-4ab9-87f4-45d8cbc38c13","name":"timeZone","type":"string","value":"=America/Chicago"},{"id":"12aeec42-9414-4d43-8837-1ff747f49305","name":"name","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.name || \"John Smith\" }}"},{"id":"36673f27-c026-4ad9-81da-ad11e71bbfb6","name":"email","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.email }}"},{"id":"469ddc00-a399-47a5-8c55-97cd3adf4143","name":"language","type":"string","value":"en"},{"id":"b191cd98-f3f7-48b1-a2e0-2c9e248a4983","name":"notes","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.notes || \"\"}}"},{"id":"783cb161-65e4-4829-ac90-5c6c2c55585f","name":"starttime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.starttime }}"},{"id":"bfcdade9-14c8-4867-8a22-3865a2bcc116","name":"endtime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.endtime }}"},{"id":"26ca39ef-48f5-41ed-990e-40c2a26d6132","name":"Tittle","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.Title }}"},{"id":"43575f7a-3873-4d74-90c5-4467c7779514","name":"customer_number","type":"string","value":"={{ $json.body.message.call.customer.number }}"}]}},"typeVersion":3.3},{"id":"b4bc5cee-d631-4aa8-a3ff-59a0b647d36a","name":"Convert time to CST America / Chicago","type":"n8n-nodes-base.code","position":[1480,1580],"parameters":{"jsCode":"// Get all input items\nconst items = $input.all();\n\n// Loop through each item\nfor (const item of items) {\n  // Get the values from the current item's JSON data\n  const startTimeUTC = item.json.starttime;\n  const endTimeUTC = item.json.endtime;\n  const targetTimeZone = item.json.timeZone; // e.g., \"America/Chicago\"\n\n  // Basic validation: ensure the necessary fields exist\n  if (!startTimeUTC || !endTimeUTC || !targetTimeZone) {\n    console.warn(`Skipping item due to missing time data or timezone. Item JSON: ${JSON.stringify(item.json)}`);\n    item.json.conversionError = \"Missing starttime, endtime, or timeZone\";\n    continue; // Move to the next item\n  }\n\n  try {\n    // --- Start Time Conversion ---\n    // Parse the original UTC ISO string using Luxon (NO $ prefix)\n    const startDt = luxon.DateTime.fromISO(startTimeUTC, { zone: 'utc' });\n\n    // Convert the DateTime object to the target timezone\n    const startDtTargetZone = startDt.setZone(targetTimeZone);\n\n    // Check if the conversion was valid\n    if (!startDtTargetZone.isValid) {\n      throw new Error(`Failed to convert start time. Reason: ${startDtTargetZone.invalidReason || 'Unknown'}`);\n    }\n\n    // Format the result back into an ISO string with the correct offset\n    item.json.starttime = startDtTargetZone.toISO();\n\n    // --- End Time Conversion ---\n    // Parse the original UTC ISO string using Luxon (NO $ prefix)\n    const endDt = luxon.DateTime.fromISO(endTimeUTC, { zone: 'utc' });\n\n    // Convert the DateTime object to the target timezone\n    const endDtTargetZone = endDt.setZone(targetTimeZone);\n\n     // Check if the conversion was valid\n    if (!endDtTargetZone.isValid) {\n      throw new Error(`Failed to convert end time. Reason: ${endDtTargetZone.invalidReason || 'Unknown'}`);\n    }\n\n    // Format the result back into an ISO string with the correct offset\n    item.json.endtime = endDtTargetZone.toISO();\n\n    // Optionally remove the error flag if conversion was successful this time\n    delete item.json.conversionError;\n\n  } catch (error) {\n    console.error(`Error converting time for item: ${JSON.stringify(item.json)}. Error: ${error.message}`);\n    // Add/update the error flag to the item's JSON\n    item.json.conversionError = error.message;\n  }\n}\n// Return the modified array of items\nreturn items;"},"typeVersion":2},{"id":"2c8b2884-14d3-4bd4-92d8-6e402ca3a8de","name":"Create Event","type":"n8n-nodes-base.googleCalendar","onError":"continueErrorOutput","position":[1700,1580],"parameters":{"end":"={{ $json.endtime }}","start":"={{ $json.starttime }}","calendar":{"__rl":true,"mode":"list","value":"pratik@customaistudio.io","cachedResultName":"pratik@customaistudio.io"},"additionalFields":{"allday":"no","summary":"={{ $json.Tittle }}","showMeAs":"opaque","attendees":["={{ $json.email }}"],"description":"={{ $json.notes }}","conferenceDataUi":{"conferenceDataValues":{"conferenceSolution":"hangoutsMeet"}}}},"credentials":{},"typeVersion":1.3},{"id":"b8890ab2-9850-4608-996d-45c8a6d3a52e","name":"Respond to Vapi","type":"n8n-nodes-base.respondToWebhook","onError":"continueRegularOutput","position":[2480,1580],"parameters":{"options":{},"respondWith":"json","responseBody":"={\n    \"results\":[\n        {\n            \"toolCallId\":\"{{ $json.results[0].toolCallId }}\",\n            \"result\":\"available:{{ $json.results[0].result }}\"\n        }\n    ]\n}"},"typeVersion":1.1,"alwaysOutputData":true},{"id":"77f75f42-46bb-47f5-8a43-55543ae46f10","name":"If the booking is confirmed then true","type":"n8n-nodes-base.if","position":[2700,1580],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"and","conditions":[{"id":"932dd430-309b-4d3b-8bf6-768f84fd2dd2","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.results[0].result }}","rightValue":"=confirmed"}]},"looseTypeValidation":true},"typeVersion":2.2},{"id":"230ddb29-67f0-4486-a6f3-f4dd3dbbee42","name":"Information to be Saved in Airtable","type":"n8n-nodes-base.set","position":[2940,1560],"parameters":{"options":{},"assignments":{"assignments":[{"id":"b103265d-86da-4256-994d-85a78f33f933","name":"startTime","type":"string","value":"={{ $('Booking Payload').item.json.startTime }}"},{"id":"a8e6e9c5-6ebb-48d8-951f-b007bed2421d","name":"endTime","type":"string","value":"={{ $('Booking Payload').item.json.endTime }}"},{"id":"d4bcb1d1-043a-4205-8488-0a67b4e7b582","name":"status","type":"string","value":"={{ $('Booking Payload').item.json.status }}"},{"id":"92ac8c99-ad94-4b3c-9c5e-ba032dac2255","name":"description","type":"string","value":"={{ $('Booking Payload').item.json.description }}"},{"id":"98c5653d-1e0e-4a6a-8630-17802d437593","name":"attendees[0].email","type":"string","value":"={{ $('Booking Payload').item.json.attendees[0].email }}"},{"id":"f94bdfc1-dc74-4675-ad29-19244fb21ebe","name":"attendees[0].responseStatus","type":"string","value":"={{ $('Booking Payload').item.json.attendees[0].responseStatus }}"},{"id":"12bd5ed5-4934-4c19-a9b9-54fe989eaa4f","name":"hangoutLink","type":"string","value":"={{ $('Booking Payload').item.json.hangoutLink }}"},{"id":"5b1f9356-7d62-4999-ae4e-86f3f20d72bf","name":"attendee.name","type":"string","value":"={{ $('bookslots_tool').item.json.body.message.toolCalls[0].function.arguments.name }}"},{"id":"6e93805e-8754-4f92-870f-7b46525f3eb3","name":"call.id","type":"string","value":"={{ $('bookslots_tool').item.json.body.message.call.id }}"},{"id":"f174e2be-3230-4fc9-970b-971aff6e9b8e","name":"assistant.name","type":"string","value":"={{ $('bookslots_tool').item.json.body.message.assistant.name }}"},{"id":"a4bc9d70-7d51-487f-b622-433e767ef71f","name":"event.id","type":"string","value":"={{ $('Create Event').item.json.id }}"},{"id":"9259b1d3-3658-4ab5-b434-364e6a84d145","name":"Title","type":"string","value":"={{ $('Booking Payload').item.json.Title }}"},{"id":"2102a7be-5d74-458f-bafd-21651e24adb1","name":"customer_number","type":"string","value":"={{ $('Input Arguments from booking tools').item.json.customer_number}}"}]}},"typeVersion":3.4},{"id":"f6c7774d-a8c7-466a-ba77-401194fe6fb4","name":"Logs the confirmed booking details","type":"n8n-nodes-base.airtable","position":[3160,1560],"parameters":{"base":{"__rl":true,"mode":"list","value":"appnj853UnMRnJ8D3","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3","cachedResultName":"Voice Receptionist Agent"},"table":{"__rl":true,"mode":"list","value":"tblF8LF9lmkHMbk7v","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3/tblF8LF9lmkHMbk7v","cachedResultName":"Appointments"},"columns":{"value":{"Name":"={{ $json.attendee.name }}","Email":"={{ $json.attendees[0].email }}","endtime":"={{ $json.endTime }}","eventId":"={{ $json.event.id }}","meetlink":"={{ $json.hangoutLink }}","starttime":"={{ $json.startTime }}","Voice Agent":"={{ [$json.assistant.name] }}","Phone Number":"={{ $json.customer_number }}","Booking Status":"={{ $json.status }}","CallRecordingId":"={{ [$json.call.id] }}","meetdescription":"={{ $json.Title }} {{ $json.description }}"},"schema":[{"id":"Email","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Email","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Phone Number","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Phone Number","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Name","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Booking Status","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Booking Status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"CallRecordingId","type":"array","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"CallRecordingId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"starttime","type":"dateTime","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"starttime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"endtime","type":"dateTime","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"endtime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"meetlink","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"meetlink","defaultMatch":false,"canBeUsedToMatch":true},{"id":"meetdescription","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"meetdescription","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Voice Agent","type":"array","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Voice Agent","defaultMatch":false,"canBeUsedToMatch":true},{"id":"eventId","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"eventId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Appointments","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"Appointments","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["Email"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{"typecast":true},"operation":"create"},"credentials":{},"typeVersion":2.1},{"id":"154bee14-9281-4b92-8204-57c5436785ba","name":"Updateslots_tool","type":"n8n-nodes-base.webhook","position":[460,2720],"webhookId":"66b278fe-97d1-4413-b6dd-4288d8ec66b2","parameters":{"path":"updateslots","options":{},"httpMethod":"POST","responseMode":"responseNode"},"typeVersion":2},{"id":"891fb4ec-3a82-4433-bebf-3f0616027e3d","name":"Input Arguments from updateslot tool","type":"n8n-nodes-base.set","position":[840,2720],"parameters":{"options":{},"assignments":{"assignments":[{"id":"6f6388ab-a233-4643-9b28-917ad6bdfe22","name":"Calls[0].id","type":"string","value":"={{ $json.body.message.toolCalls[0].id }}"},{"id":"40888d2c-b99d-401d-a6b9-944ba41543c6","name":"name","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.name }}"},{"id":"17be6cf6-8c48-4a4e-a0e8-b5b714f94242","name":"email","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.email }}"},{"id":"d06fd547-39c1-457b-8422-393f140aead6","name":"starttime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.starttime }}"},{"id":"c224df67-ec82-40f3-9af2-3472731a57fa","name":"endtime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.endtime }}"},{"id":"b2fb0887-5545-409c-bba8-fae76a71f660","name":"call.id","type":"string","value":"={{ $json.body.message.call.id }}"},{"id":"19efa4c6-25e0-4fe8-a00e-0b37f16b6de0","name":"Rescheduled_starttime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.Rescheduled_starttime }}"},{"id":"ad47dfdb-66fa-478d-899f-1d9d202aac6f","name":"Rescheduled_endttime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.Rescheduled_endttime }}"},{"id":"6d1bf6c0-a4b4-41d4-826e-e7c73f920905","name":"customer_number","type":"string","value":"={{ $json.body.message.call.customer.number }}"}]}},"typeVersion":3.4},{"id":"617a7742-299a-4c91-be82-cba598d1bb82","name":"Checks if required info is provided.","type":"n8n-nodes-base.if","position":[1060,2720],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"and","conditions":[{"id":"87304425-5f17-4637-8aa3-cd84b2f8d856","operator":{"type":"string","operation":"exists","singleValue":true},"leftValue":"={{ $json.name }}","rightValue":""},{"id":"fdc6ffb0-f234-4869-8f5e-482c394ab860","operator":{"type":"string","operation":"exists","singleValue":true},"leftValue":"={{ $json.email }}","rightValue":""},{"id":"7950d7bc-7416-48b6-8ec5-a635a9161013","operator":{"type":"dateTime","operation":"exists","singleValue":true},"leftValue":"={{ $json.Rescheduled_starttime }}","rightValue":"={{ $json.Rescheduledtime }}"},{"id":"aa54ee15-1273-48b0-863f-939597af04e6","operator":{"type":"dateTime","operation":"exists","singleValue":true},"leftValue":"={{ $json.Rescheduled_endttime }}","rightValue":""},{"id":"8ceefa9d-360c-48b6-8faf-e156459f2c07","operator":{"type":"dateTime","operation":"exists","singleValue":true},"leftValue":"={{ $json.starttime }}","rightValue":""}]},"looseTypeValidation":true},"typeVersion":2.2},{"id":"dded1cfa-ce89-481f-967b-6843854a32bd","name":"Finds original appointment","type":"n8n-nodes-base.airtable","maxTries":2,"position":[1600,2560],"parameters":{"base":{"__rl":true,"mode":"list","value":"appnj853UnMRnJ8D3","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3","cachedResultName":"Voice Receptionist Agent"},"table":{"__rl":true,"mode":"list","value":"tblF8LF9lmkHMbk7v","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3/tblF8LF9lmkHMbk7v","cachedResultName":"Appointments"},"options":{"fields":["Email","Name","starttime","eventId"]},"operation":"search","filterByFormula":"={Phone Number} = (\"{{ $json.customer_number }}\")"},"credentials":{},"retryOnFail":false,"typeVersion":2.1,"alwaysOutputData":false},{"id":"a3fd9971-20bb-414a-b06c-1af4da053241","name":"Response with Error","type":"n8n-nodes-base.respondToWebhook","position":[1780,2840],"parameters":{"options":{}},"typeVersion":1.1},{"id":"0731f0ae-fbdb-4149-890a-0a44c95b2691","name":"Update Event","type":"n8n-nodes-base.googleCalendar","onError":"continueErrorOutput","position":[1980,2560],"parameters":{"eventId":"={{ $json.eventId }}","calendar":{"__rl":true,"mode":"list","value":"pratik@customaistudio.io","cachedResultName":"pratik@customaistudio.io"},"operation":"update","updateFields":{"end":"={{ $('Checks if required info is provided.').item.json.Rescheduled_endttime }}","start":"={{ $('Checks if required info is provided.').item.json.Rescheduled_starttime }}","allday":"no"}},"credentials":{},"typeVersion":1.3},{"id":"1e7af704-6c5d-4e6b-a606-2c5c7ef64b10","name":"Updates Airtable record","type":"n8n-nodes-base.airtable","position":[2280,2440],"parameters":{"base":{"__rl":true,"mode":"list","value":"appnj853UnMRnJ8D3","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3","cachedResultName":"Voice Receptionist Agent"},"table":{"__rl":true,"mode":"list","value":"tblF8LF9lmkHMbk7v","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3/tblF8LF9lmkHMbk7v","cachedResultName":"Appointments"},"columns":{"value":{"endtime":"={{ $json.end.dateTime }}","eventId":"={{ $('Finds original appointment').item.json.eventId }}","starttime":"={{ $json.start.dateTime }}","Booking Status":"Updated/Rescheduled"},"schema":[{"id":"id","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"id","defaultMatch":true},{"id":"Email","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Email","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Phone Number","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Phone Number","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Name","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Booking Status","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Booking Status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"CallRecordingId","type":"array","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"CallRecordingId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"starttime","type":"dateTime","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"starttime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"endtime","type":"dateTime","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"endtime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"meetlink","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"meetlink","defaultMatch":false,"canBeUsedToMatch":true},{"id":"meetdescription","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"meetdescription","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Voice Agent","type":"array","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Voice Agent","defaultMatch":false,"canBeUsedToMatch":true},{"id":"eventId","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"eventId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Appointments","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"Appointments","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["eventId"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update"},"credentials":{},"typeVersion":2.1},{"id":"5a74d949-f08e-422c-afde-e41690a8512b","name":"Response & call_id","type":"n8n-nodes-base.set","position":[2620,2580],"parameters":{"options":{},"assignments":{"assignments":[{"id":"074d1ef3-e96b-4149-a12c-b8aa71c9c117","name":"results[0].toolCallId","type":"string","value":"={{ $('Updateslots_tool').item.json.body.message.toolCalls[0].id }}"},{"id":"098bb88d-9b17-4aeb-850c-819406aa0f3b","name":"results[0].result","type":"string","value":"={{ $json.error || $json.fields['Booking Status']  }}"}]}},"typeVersion":3.4},{"id":"bb7dc099-c4ac-48d4-bf8c-50f4f8858dd4","name":"Respond to Vapi about Updating slots","type":"n8n-nodes-base.respondToWebhook","position":[2820,2580],"parameters":{"options":{},"respondWith":"json","responseBody":"={\n    \"results\":[\n        {\n            \"toolCallId\":\"{{ $json.results[0].toolCallId }}\",\n            \"result\":\"{{ $json.results[0].result }}\"\n        }\n    ]\n}"},"typeVersion":1.1},{"id":"2154c9c8-acd3-4144-9fa6-f6f7de7bbf48","name":"CancelSlots_tool","type":"n8n-nodes-base.webhook","position":[440,3620],"webhookId":"00fedd5a-c03d-4302-b8e0-22c79f26ed05","parameters":{"path":"cancelslots","options":{},"httpMethod":"POST","responseMode":"responseNode"},"typeVersion":2},{"id":"aeabd266-4b0e-436f-9c8c-607fb7b6734a","name":"Input Arguments from cancelslot tool","type":"n8n-nodes-base.set","position":[800,3620],"parameters":{"options":{},"assignments":{"assignments":[{"id":"6f6388ab-a233-4643-9b28-917ad6bdfe22","name":"Calls[0].id","type":"string","value":"={{ $json.body.message.toolCalls[0].id }}"},{"id":"40888d2c-b99d-401d-a6b9-944ba41543c6","name":"name","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.name }}"},{"id":"17be6cf6-8c48-4a4e-a0e8-b5b714f94242","name":"email","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.email }}"},{"id":"d06fd547-39c1-457b-8422-393f140aead6","name":"starttime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.starttime }}"},{"id":"0a0243b2-afc4-44f1-92cd-81572df79cc5","name":"Cancelnotes","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.Cancelnotes }}"},{"id":"b2fb0887-5545-409c-bba8-fae76a71f660","name":"call.id","type":"string","value":"={{ $json.body.message.call.id }}"},{"id":"8d528786-75d7-466e-8e8f-2013e4638bc2","name":"customer_number","type":"string","value":"={{ $json.body.message.call.customer.number }}"}]}},"typeVersion":3.4},{"id":"b702973e-15f0-4bbe-98ac-d4af7a57cff1","name":"Checks if required info is provided for cancelation","type":"n8n-nodes-base.if","position":[1020,3620],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"and","conditions":[{"id":"87304425-5f17-4637-8aa3-cd84b2f8d856","operator":{"type":"string","operation":"exists","singleValue":true},"leftValue":"={{ $json.name }}","rightValue":""},{"id":"fdc6ffb0-f234-4869-8f5e-482c394ab860","operator":{"type":"string","operation":"exists","singleValue":true},"leftValue":"={{ $json.email }}","rightValue":""},{"id":"c0b869e4-9490-4c01-b138-835bb34eb1ba","operator":{"type":"dateTime","operation":"exists","singleValue":true},"leftValue":"={{ $json.starttime }}","rightValue":""}]},"looseTypeValidation":true},"typeVersion":2.2},{"id":"c5e49060-7b76-4622-bc23-b389f1665215","name":"Finds the appointment record","type":"n8n-nodes-base.airtable","position":[1300,3560],"parameters":{"base":{"__rl":true,"mode":"list","value":"appnj853UnMRnJ8D3","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3","cachedResultName":"Voice Receptionist Agent"},"table":{"__rl":true,"mode":"list","value":"tblF8LF9lmkHMbk7v","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3/tblF8LF9lmkHMbk7v","cachedResultName":"Appointments"},"options":{"fields":["Email","Name","starttime","eventId"]},"operation":"search","filterByFormula":"={Phone Number} = (\"{{ $json.customer_number }}\")"},"credentials":{},"typeVersion":2.1,"alwaysOutputData":true},{"id":"dd83c017-6f5b-49b4-83f9-ec2f33ca5ed0","name":"Build Error Response","type":"n8n-nodes-base.set","position":[1300,3780],"parameters":{"options":{},"assignments":{"assignments":[{"id":"5cb05b10-e916-459e-84a2-9c314a859a07","name":"results[0].toolCallId","type":"string","value":"={{ $('Input Arguments from booking tools').item.json.toolCallId }}"},{"id":"552246f9-7afd-404e-9fb3-cb38c7447359","name":"results[0].result","type":"string","value":"=You must provide an email, name and starttime to call this tool"}]}},"typeVersion":3.4},{"id":"ca74e845-ee23-4f8a-ba8e-789186fe7add","name":"Respond with Error to Vapi","type":"n8n-nodes-base.respondToWebhook","position":[1500,3780],"parameters":{"options":{}},"typeVersion":1.1},{"id":"ad3c2ad0-ba5e-48a6-865f-a8da63173562","name":"Delete Event","type":"n8n-nodes-base.googleCalendar","onError":"continueErrorOutput","position":[1720,3560],"parameters":{"eventId":"={{ $json.eventId }}","options":{"sendUpdates":"all"},"calendar":{"__rl":true,"mode":"list","value":"pratik@customaistudio.io","cachedResultName":"pratik@customaistudio.io"},"operation":"delete"},"credentials":{},"typeVersion":1.3},{"id":"177a1297-8e96-4d04-a0ff-e16aab71d5b9","name":"Update Airtable record","type":"n8n-nodes-base.airtable","position":[1940,3440],"parameters":{"base":{"__rl":true,"mode":"list","value":"appnj853UnMRnJ8D3","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3","cachedResultName":"Voice Receptionist Agent"},"table":{"__rl":true,"mode":"list","value":"tblF8LF9lmkHMbk7v","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3/tblF8LF9lmkHMbk7v","cachedResultName":"Appointments"},"columns":{"value":{"eventId":"={{ $('Finds the appointment record').item.json.eventId }}","Booking Status":"Canceled"},"schema":[{"id":"id","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"id","defaultMatch":true},{"id":"Email","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Email","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Phone Number","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Phone Number","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Name","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Booking Status","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Booking Status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"CallRecordingId","type":"array","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"CallRecordingId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"starttime","type":"dateTime","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"starttime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"endtime","type":"dateTime","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"endtime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"meetlink","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"meetlink","defaultMatch":false,"canBeUsedToMatch":true},{"id":"meetdescription","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"meetdescription","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Voice Agent","type":"array","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Voice Agent","defaultMatch":false,"canBeUsedToMatch":true},{"id":"eventId","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"eventId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Appointments","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"Appointments","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["eventId"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update"},"credentials":{},"typeVersion":2.1},{"id":"4d0c155c-68ad-4f70-b9c6-0dbd4db70fd1","name":"Call_id & Response","type":"n8n-nodes-base.set","position":[2160,3580],"parameters":{"options":{},"assignments":{"assignments":[{"id":"074d1ef3-e96b-4149-a12c-b8aa71c9c117","name":"results[0].toolCallId","type":"string","value":"={{ $('CancelSlots_tool').item.json.body.message.toolCalls[0].id }}"},{"id":"098bb88d-9b17-4aeb-850c-819406aa0f3b","name":"results[0].result","type":"string","value":"={{ $json.error || $json.fields['Booking Status']  }}"}]}},"typeVersion":3.4},{"id":"41ff13bf-0793-4082-8be6-51f0617ab0f8","name":"Respond to Vapi about cancelation","type":"n8n-nodes-base.respondToWebhook","position":[2400,3580],"parameters":{"options":{},"respondWith":"json","responseBody":"={\n    \"results\":[\n        {\n            \"toolCallId\":\"{{ $json.results[0].toolCallId }}\",\n            \"result\":\"{{ $json.results[0].result }}\"\n        }\n    ]\n}"},"typeVersion":1.1},{"id":"599592b1-214c-4e99-84f6-e244e690ed79","name":"call_results","type":"n8n-nodes-base.webhook","position":[440,4300],"webhookId":"4a6205cd-4277-4686-8008-540b802b99fe","parameters":{"path":"callresults","options":{},"httpMethod":"POST"},"typeVersion":2},{"id":"baf3ce79-f302-42ad-bb7e-49f2d9197eae","name":"All Input Arguments","type":"n8n-nodes-base.set","position":[720,4300],"parameters":{"options":{"ignoreConversionErrors":true},"assignments":{"assignments":[{"id":"fd00208a-e833-4834-8c37-0034c44fb47d","name":"transcript","type":"string","value":"={{ $json.body.message.artifact.transcript }}"},{"id":"b72ffa4d-aef3-4d7c-8b81-9238a3c5890b","name":"recordingUrl","type":"string","value":"={{ $json.body.message.artifact.recordingUrl }}"},{"id":"e45d90de-0103-46ba-9fcb-f4c969816da0","name":"call.summary","type":"string","value":"={{ $json.body.message.analysis.summary }}"},{"id":"b0a5557f-483f-47c9-955a-c12ce84f270b","name":"cost","type":"number","value":"={{ $json.body.message.cost }}"},{"id":"2bfcfe4f-4eaf-4274-b3f2-cdaea8c2cc46","name":"call.id","type":"string","value":"={{ $json.body.message.call.id }}"},{"id":"2b7b1638-0d0e-4c48-9989-287fd4e0babd","name":"call.orgId","type":"string","value":"={{ $json.body.message.call.orgId }}"},{"id":"adf4d062-bbfd-4f97-bda4-bdfec1e40ee4","name":"assistant.name","type":"string","value":"={{ $json.body.message.assistant.name }}"},{"id":"3c2af504-d320-45f0-9008-79b3bc1ff897","name":"startedAt","type":"string","value":"={{ $json.body.message.startedAt }}"},{"id":"0486dbfa-ca10-45b5-a79a-3ce1064f13fa","name":"endedAt","type":"string","value":"={{ $json.body.message.endedAt }}"},{"id":"bf97b5eb-5baa-4a87-b34e-2f64c97c0d42","name":"assistant.id","type":"string","value":"={{ $json.body.message.assistant.id }}"},{"id":"58ee9b29-7aa1-4a15-bf83-606287a964a6","name":"assistant.model","type":"string","value":"={{ $json.body.message.assistant.model.model }}"},{"id":"36e2bbef-e12d-4fc4-a0af-bb65aa446023","name":"body.message.assistant","type":"object","value":"={{ $json.body.message.assistant }}"},{"id":"dfa93dbb-67dc-417b-874a-32fbd55d92b0","name":"assistantId","type":"string","value":"={{ $json.body.message.call.assistantId }}"},{"id":"4bc2b480-92a1-470e-bdf0-d6609f346ed2","name":"body.message.assistant.model.emotionRecognitionEnabled","type":"boolean","value":"={{ $json.body.message.assistant.model.emotionRecognitionEnabled }}"},{"id":"acb64bba-e295-4dd0-9ab3-b4166ef5d0ad","name":"customer.number","type":"string","value":"={{ $json.body.message.call.customer.number }}"}]}},"typeVersion":3.4},{"id":"f3394750-7438-47e9-8aa3-996accfa9bac","name":"Save all information","type":"n8n-nodes-base.airtable","position":[900,4300],"parameters":{"base":{"__rl":true,"mode":"list","value":"appnj853UnMRnJ8D3","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3","cachedResultName":"Voice Receptionist Agent"},"table":{"__rl":true,"mode":"list","value":"tbl1b6vMhq9IT9JEZ","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3/tbl1b6vMhq9IT9JEZ","cachedResultName":"Call Recording"},"columns":{"value":{"Cost":"={{ $json.cost }}","endedAt":"={{ $json.endedAt }}","startedAt":"={{ $json.startedAt }}","transcript":"={{ $json.transcript }}","callsummary":"={{ $json.call.summary }}","customer_Number":"={{ $json.customer.number }}","callrecording_id":"={{ $json.call.id }}","Call recording Url":"={{ $json.recordingUrl }}"},"schema":[{"id":"id","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"id","defaultMatch":true},{"id":"callrecording_id","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"callrecording_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Cost","type":"number","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Cost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Call recording Url","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Call recording Url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"transcript","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"transcript","defaultMatch":false,"canBeUsedToMatch":true},{"id":"customer_Number","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"customer_Number","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Appointments","type":"array","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Appointments","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Appointment time (from Appointments)","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"Appointment time (from Appointments)","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Voice Agent (from Appointments)","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"Voice Agent (from Appointments)","defaultMatch":false,"canBeUsedToMatch":true},{"id":"startedAt","type":"dateTime","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"startedAt","defaultMatch":false,"canBeUsedToMatch":true},{"id":"endedAt","type":"dateTime","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"endedAt","defaultMatch":false,"canBeUsedToMatch":true},{"id":"call_Length (in secs)","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"call_Length (in secs)","defaultMatch":false,"canBeUsedToMatch":true},{"id":"callsummary","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"callsummary","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["callrecording_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{"typecast":true},"operation":"upsert"},"credentials":{},"typeVersion":2.1},{"id":"5671dcff-8894-42a8-af77-df01d0b6c190","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[-1800,1980],"parameters":{"color":4,"width":1680,"height":2700,"content":"# Vapi System Prompt\n\n### First Message: \nHi, this is Ellie with Harrison Climate Solutions how can I help you?\n\n----**END**----\n\n### System Prompt:\n\n[Identity]  \nYou are Ellie, the friendly and knowledgeable voice receptionist for Harrison Climate Solutions, an HVAC service company based in San Antonio, Texas.\n- Current Date and Time: {{\"now\" | date: \"%b %d, %Y, %I:%M %p\", \"America/Chicago\"}}\n\n[Style]  \n- Use a friendly, conversational tone with a hint of Texan warmth.\n- Be warm, approachable, and slightly humorous to create a comfortable and friendly experience for callers.\n- Use casual, conversational language, incorporating friendly fillers like “Umm...,” “Well...,” or “I mean.”\n- Keep responses brief and engaging, mirroring a natural conversation style to suit the voice format.\n\n[Response Guideline]  \n- Use a friendly and conversational tone, never saying \"Asterisk\" or similar technical terms.\n- Limit responses to essential information only, breaking up information into bite-sized pieces when possible.\n- Remember this is a telephone conversation. Give the caller opportunities to talk.\n- Politely redirect any off-topic questions back to Harrison Climate Solutions' services or appointment scheduling.\n- If they hadn't requested an endtime always assume for 30 mins meeting.\n- When asking for EMAIL always say: \" Can you spell your email please ? \".\n\n[Reminder]  \n- Use your knowledge base to access more information about the business.\n- Current Date and Time: {{\"now\" | date: \"%b %d, %Y, %I:%M %p\", \"America/Chicago\"}}\n- Do not repeat the caller.\n- Do not Book Calls on Saturday and Sunday and on Holidays (Always getslots)\n- Mention that Harrison Climate Solutions operates Monday through Friday, 8 a.m. to 5 p.m.\n- ONLY MOVE FORWARD when you have correct NAME, EMAIL and TIMMINGS. \n\n- When people ask about your phone number, your phone number is 4158923245\n **Guideline**\nWhen speaking the phone number, transform the format as follows:\n- Input formats like 4158923245, (415) 892-3245, or 415-892-3245\n- Should be pronounced as: \"four one five - eight nine two - three two four five\"\n- Important: Don't omit the space around the dash when speaking\n\nAlways ask to spell the email out. \n**How to spell out**\nThe possible email format is name@company.com\nto spell out an email address is N - A - M - E - @company.com,\nYOU MUST read them out with regular words like 'company' or 'blue'.\nFor names, you must read them out letter by letter, for example, 'P - R - A - T - I - K'.\n@ is pronounced by \"at\" or \"at direct\".\n\n- State Numbers, Times & Dates Slowly\nFor 1:00 PM, say “One PM.”\nFor 3:30 PM, say “Three thirty PM.”\nFor 8:45 AM, say “Eight forty-five AM.”\nNever say “O’Clock.” Instead just say O-Clock never O'clock, This is non-negotiable—always say “AM” or “PM.\n\n[Tool Usage Guidelines]  \n\n1. **Booking Appointments (BookSlot Tool)**  \n   - **Purpose**: Use the `BookSlot` function to finalize an appointment when all required details (name, email, start time, and notes) are gathered.\n   - **Parameters**: Ensure the following parameters are complete before calling:\n     - `name`: The attendee's name (never make up or use a placeholder).\n     - `email`: The attendee's email (never make up or use a placeholder).\n     - `start`: Appointment start time in ISO 8601 format (e.g., `\"2023-04-25T15:00:00Z\"`) in America/Chicago timezone.\n     - `notes`: A brief description (2-3 sentences) summarizing what the customer is looking for and why they need the appointment.\n \n2. **Finding Available Slots (GetSlots Tool)**  \n   - **Purpose**: Use `GetSlots` to check available time slots for an appointment when date parameters (start and end time in ISO format) are known.\n   - **Parameters**:\n     - `startTime`: Start of the search window.\n     - `endTime`: End of the search window.\n   - **Directive**: Immediately call `GetSlots` without waiting for any additional user response if you have all required information for `startTime` and `endTime`. Do not pause or expect further input before calling.\n\n3. **Canceling Appointments (CancelSlots Tool)**  \n   - **Purpose**: Use the `CancelSlots` function to cancel an appointment when all required details (name, email, start time) are gathered.\n   - **Parameters**: Ensure the following parameters are complete before calling:\n     - `name`: The attendee's name (never make up or use a placeholder).\n     - `email`: The attendee's email (never make up or use a placeholder).\n     - `start`: Appointment start time in ISO 8601 format (e.g., `\"2023-04-25T15:00:00Z\"`)  in America/Chicago timezone.\n     - `Cancelnotes`: A brief description (2-3 sentences) summarizing why the customer want to cancel the appointment.\n\n4. **Transferring Calls (TransferCall Tool)**\n**Purpose**: Use the `TransferCall` function to connect the caller to Sam’s forwarding number when absolutely necessary.\n   - **When to Use**: \n     - If the caller says the secret phrase \"Hot Brisket.\"\n     - If you determine the situation is a genuine emergency and requires immediate attention.\n   - **Directive**: Use the `TransferCall` tool immediately when one of the above conditions is met, forwarding the caller to Sam’s specified phone number. Do not attempt to handle emergencies yourself, and do not wait for caller feedback before initiating the transfer. Transfer the call to Sam.\n\n[Task]\n1. **Service Questions**\n   - If the caller has questions about services, provide a concise description of the relevant services based on company offerings.\n   - Mention popular seasonal promotions as relevant (e.g., furnace tune-ups in winter, AC installation deals in summer).\n   - For questions about pricing, explain that Harrison Climate Solutions offers free estimates and stress the transparency of pricing with no hidden fees.\n\n2. **Appointment Scheduling**\n   - Do not try to schedule an appointment for a time in the past. Give a friendly joke about scheduling in the past if they try.\n   - If the caller is interested in scheduling an appointment, **follow these steps**:\n      1. Gather attendee’s email, ask them to spell their email: \" Can you spell your email \" eg: \" P-R-A-T-I-K@gmail.com \", name , preferred time, and reason for the appointment. ONLY MOVE FORWARD when you have correct NAME, EMAIL and TIMMINGS. \n      2. If you have both `startTime` and `endTime`, **immediately call `GetSlots` to check for availability**. Do not wait for caller feedback after confirming you’ll check.\n      3. Only suggest available slots based on confirmed results from `GetSlots`. Never make up availability if none is returned.\n      4. If `GetSlots` returns more than three options, offer just two to three choices to help the caller decide.\n      5. If no availability is found, inform the caller courteously that slots are fully booked and suggest calling back later.\n   - Once a suitable time is identified, use the `BookSlot` tool to schedule the appointment, and confirm the details with the caller. **Only use this tool to book an appointment. Never make up an appointment booking. Do not wait for caller feedback before calling this tool if you have everything you need.**\n   - Mention that Harrison Climate Solutions operates Monday through Friday, 8 a.m. to 5 p.m. If emergency then only 24-hour, 7-day-a-week if needed in America/Chicago time zone.\n\n3. ** Update Appointment** \n- if the caller is interested in Rescheduling/Updating their booking **follow the steps**:\n   1. Gather attendee's name and ask them to spell their email : \" Can you spell your email \", Previous booking timings like starttime and rescheduling time for rescheduling. (ONLY MOVE FORWARD when you have correct NAME, EMAIL and TIMMINGS. )\n   2. If you have 'starttime' and email, **immediately call 'GetSlots' to check if time is not available . Do not wait for caller feedback after confirming you’ll check. \n  3. if time is not available, then Call the 'UpdateSlots' tool for rescheduling.\n  4. If time is available, inform the caller that there is no appointment booked at that time.\n\n4. **Cancel Appointment **\n  - if the caller is interested in canceling a booking, **follow the steps**:\n    1. Gather attendee's name and ask them to spell their email : \" Can you spell your email \", timings and if possible reason for cancelation. ( ONLY MOVE FORWARD when you have correct NAME, EMAIL and TIMMINGS. )\n    2. If you have 'starttime' and email, **immediately call 'GetSlots' to check if time is not available . Do not wait for caller feedback after confirming you’ll check. \n    3. if time is not available, then insists caller to 'Update appointment' first and if he don't want to update appointment then use the 'CancelSlots' tool to cancel the appointment. \n    4. If time is available, inform the caller that there is no appointment booked at that time.\n\n---**END**---"},"typeVersion":1},{"id":"44596616-27ba-47c0-8a6d-cf50f86a136e","name":"Sticky Note15","type":"n8n-nodes-base.stickyNote","position":[280,900],"parameters":{"color":7,"width":191,"height":80,"content":"**☝️ Set up `Getslot` tool and Webhook in Vapi**\n"},"typeVersion":1},{"id":"226635e5-05cf-4da6-bbd5-304e458a7112","name":"Sticky Note16","type":"n8n-nodes-base.stickyNote","position":[400,1960],"parameters":{"color":7,"width":191,"height":80,"content":"**☝️ Set up `Bookslot` tool and Webhook in Vapi**\n"},"typeVersion":1},{"id":"dd2caca4-8669-447f-85ee-b0d829e0e8c4","name":"Sticky Note17","type":"n8n-nodes-base.stickyNote","position":[460,2880],"parameters":{"color":7,"width":191,"height":80,"content":"**☝️ Set up `Updateslot` tool and Webhook in Vapi**\n"},"typeVersion":1},{"id":"be40ca37-c272-4170-a6b1-cf17a28c37ba","name":"Sticky Note18","type":"n8n-nodes-base.stickyNote","position":[440,3780],"parameters":{"color":7,"width":191,"height":80,"content":"**☝️ Set up `Cancelslot` tool and Webhook in Vapi**\n"},"typeVersion":1},{"id":"98af9e21-fb6e-41ef-a15e-f0b914e1dc8d","name":"Sticky Note19","type":"n8n-nodes-base.stickyNote","position":[440,4440],"parameters":{"color":7,"width":191,"height":80,"content":"**☝️ Set up `call_results` as a Server Webhook in Vapi**\n"},"typeVersion":1},{"id":"ab8f9a65-74b1-42ce-ba65-8f0e0e390839","name":"Sticky Note9","type":"n8n-nodes-base.stickyNote","position":[-1800,340],"parameters":{"color":7,"width":1460,"height":1540,"content":"## Voice Receptionist for Appointment Management (tools)\n\n## Introduction\n### What This Template Does:\n- This n8n workflow template automates appointment management using a voice AI receptionist powered by Vapi. It integrates Vapi with Google Calendar for real-time scheduling and Airtable for logging and data management. Agent checks availability, books new appointments, reschedules existing ones, or cancels appointments directly within Google Calendar.\n\n### Problem It Solves:\n- Managing appointment scheduling manually can be time-consuming, and limited by business hours. This template solves these issues by providing an automated, 24/7 (within configured business rules) voice-based scheduling system. It frees up human staff from routine scheduling tasks, reduces booking errors, ensures appointments are logged consistently, and enhances the customer experience by offering immediate scheduling capabilities over the phone. It also captures valuable call data like recordings, summaries, and costs for analysis.\n\n## Setup Instructions\n\n### Prerequisites:\n- An active n8n instance.\n- A Vapi account for the voice agent.\n- A Google account with access to Google Calendar.\n- An Airtable account.\n- API Keys/Credentials for Google Calendar and Airtable configured in your n8n instance.\n\n## Step-by-Step Setup:\n### 1. Copy Airtable Base:\n- Duplicate the provided Airtable base structure to your own Airtable account using this link: https://airtable.com/appxDqRoEgG5sF2gu/shrnZU0D29TPMCjpt\n- Note: The n8n workflow is configured to work with the specific tables and fields in this base (\"Appointments\" and \"Call Recording\" tables).\n\n### 2. Import n8n Workflow:\n- Import the provided n8n workflow JSON into your n8n instance.\n\n### 3. Configure n8n Credentials:\n- Locate the Google Calendar nodes within the workflow (e.g., \"Check Availability\", \"Get All Calendar Events\", \"Create Event\", \"Update Event\", \"Delete Event\"). Ensure they are configured to use your Google Calendar credentials in n8n. Select the correct calendar to manage.\n- Locate the Airtable nodes (e.g., \"Logs the confirmed booking details\", \"Finds original appointment\", \"Updates Airtable record\", \"Save all information\"). Ensure they are configured with your Airtable credentials and point to the correct Base and Tables you created in Step 1.\n\n### 4. Activate the n8n Workflow:\n- Save and activate the n8n workflow. This generates the live Webhook URLs needed for Vapi.\n\n### 5. Configure Vapi Assistant:\n- **System Prompt:** Copy the system prompt provided in the large sticky note within the n8n workflow. Adapt it as needed (e.g., business name, hours) and paste it into your Vapi Assistant's System Prompt configuration. This prompt instructs the AI on its role, rules, and how/when to use the tools.\n\n- **Tools Setup:** In your Vapi Assistant configuration, define the following 4 tools:\n  - Getslots Tool:\n    - Purpose: To check calendar availability.\n    - Webhook URL: Copy the Production URL from the \"Getslot_tool\" Webhook node in your active n8n workflow (path: /getslots) and paste it here.\n  - Bookslots Tool:\n    - Purpose: To create a new calendar event.\n    - Webhook URL: Copy the Production URL from the \"bookslots_tool\" Webhook node in your active n8n workflow (path: /bookslots) and paste it here.\n  - Updateslots Tool:\n    - Purpose: To modify an existing calendar event.\n    - Webhook URL: Copy the Production URL from the \"Updateslots_tool\" Webhook node in your active n8n workflow (path: /updateslots) and paste it here.\n  - Cancelslots Tool:\n    - Purpose: To delete a calendar event.\n    - Webhook URL: Copy the Production URL from the \"CancelSlots_tool\" Webhook node in your active n8n workflow (path: /cancelslots) and paste it here.\n- **Server Webhook (End of Call Report):**\n  - In Vapi's server configuration section (often under webhooks or reporting), find the setting for the end-of-call-report or similar event.\n  - Copy the Production URL from the \"call_results\" Webhook node in your active n8n workflow (path: /callresults).\n  - Paste this URL into the Vapi configuration for the end-of-call server webhook. This allows n8n to receive and log call summaries, recordings, etc., after the call ends.\n\n## Video Walkthrough (coming soon)\n### [🎥 Watch set up video (~2min)](https://www.loom.com/share/d379895004374ddc85dc9171ca37c139?sid=0996f0d2-aff2-45a7-aae9-c62df4fb0799)\n"},"typeVersion":1},{"id":"8d984e05-5bca-4c70-beee-16f7cd70594e","name":"Sticky Note12","type":"n8n-nodes-base.stickyNote","position":[40,300],"parameters":{"color":7,"width":3700,"height":4400,"content":"# Workflow"},"typeVersion":1}],"pinData":{},"connections":{"Sort":{"main":[[{"node":"Format response","type":"main","index":0}]]},"Enrich Date":{"main":[[{"node":"Build Response Payload","type":"main","index":0}]]},"Escape Json":{"main":[[{"node":"Convert time to CST America / Chicago","type":"main","index":0}]]},"Create Event":{"main":[[{"node":"Booking Payload","type":"main","index":0}],[{"node":"Add Friendly Error","type":"main","index":0}]]},"Delete Event":{"main":[[{"node":"Update Airtable record","type":"main","index":0}],[{"node":"Call_id & Response","type":"main","index":0}]]},"Getslot_tool":{"main":[[{"node":"Input Arguments","type":"main","index":0}]]},"Update Event":{"main":[[{"node":"Updates Airtable record","type":"main","index":0}],[{"node":"Response & call_id","type":"main","index":0}]]},"call_results":{"main":[[{"node":"All Input Arguments","type":"main","index":0}]]},"Flatten Slots":{"main":[[{"node":"Enrich Date","type":"main","index":0}]]},"Error Response":{"main":[[{"node":"Respond to Vapi","type":"main","index":0}]]},"bookslots_tool":{"main":[[{"node":"Input Arguments from booking tools","type":"main","index":0}]]},"Booking Payload":{"main":[[{"node":"Success Response","type":"main","index":0}]]},"Format response":{"main":[[{"node":"Available Start Times & Ranges","type":"main","index":0}]]},"Input Arguments":{"main":[[{"node":"Check Availability","type":"main","index":0}]]},"Respond to Vapi":{"main":[[{"node":"If the booking is confirmed then true","type":"main","index":0}]]},"CancelSlots_tool":{"main":[[{"node":"Input Arguments from cancelslot tool","type":"main","index":0}]]},"Success Response":{"main":[[{"node":"Respond to Vapi","type":"main","index":0}]]},"Updateslots_tool":{"main":[[{"node":"Input Arguments from updateslot tool","type":"main","index":0}]]},"Add Friendly Error":{"main":[[{"node":"Error Response","type":"main","index":0}]]},"Call_id & Response":{"main":[[{"node":"Respond to Vapi about cancelation","type":"main","index":0}]]},"Check Availability":{"main":[[{"node":"Check if time is available or not","type":"main","index":0}]]},"Response & call_id":{"main":[[{"node":"Respond to Vapi about Updating slots","type":"main","index":0}]]},"All Input Arguments":{"main":[[{"node":"Save all information","type":"main","index":0}]]},"Has all information":{"main":[[{"node":"Escape Json","type":"main","index":0}],[{"node":"Build Error Response Payload","type":"main","index":0}]]},"Build Error Response":{"main":[[{"node":"Respond with Error to Vapi","type":"main","index":0}]]},"Build Response Payload":{"main":[[{"node":"Convert into Json format for Vapi","type":"main","index":0}]]},"Update Airtable record":{"main":[[{"node":"Call_id & Response","type":"main","index":0}]]},"Get All Calendar Events":{"main":[[{"node":"Extract start, end and name","type":"main","index":0}]]},"Updates Airtable record":{"main":[[{"node":"Response & call_id","type":"main","index":0}]]},"Finds original appointment":{"main":[[{"node":"Update Event","type":"main","index":0}]]},"Extract start, end and name":{"main":[[{"node":"Sort","type":"main","index":0}]]},"Build Error Response Payload":{"main":[[{"node":"Respond with Error","type":"main","index":0}]]},"Finds the appointment record":{"main":[[{"node":"Delete Event","type":"main","index":0}]]},"Build Error Response Payload2":{"main":[[{"node":"Response with Error","type":"main","index":0}]]},"Available Start Times & Ranges":{"main":[[{"node":"Flatten Slots","type":"main","index":0}]]},"Time available (true) & Call_id":{"main":[[{"node":"Response","type":"main","index":0}]]},"Check if time is available or not":{"main":[[{"node":"Time available (true) & Call_id","type":"main","index":0}],[{"node":"Get All Calendar Events","type":"main","index":0}]]},"Convert into Json format for Vapi":{"main":[[{"node":"Response to Vapi","type":"main","index":0}]]},"Input Arguments from booking tools":{"main":[[{"node":"Has all information","type":"main","index":0}]]},"Information to be Saved in Airtable":{"main":[[{"node":"Logs the confirmed booking details","type":"main","index":0}]]},"Checks if required info is provided.":{"main":[[{"node":"Finds original appointment","type":"main","index":0}],[{"node":"Build Error Response Payload2","type":"main","index":0}]]},"Input Arguments from cancelslot tool":{"main":[[{"node":"Checks if required info is provided for cancelation","type":"main","index":0}]]},"Input Arguments from updateslot tool":{"main":[[{"node":"Checks if required info is provided.","type":"main","index":0}]]},"Convert time to CST America / Chicago":{"main":[[{"node":"Create Event","type":"main","index":0}]]},"If the booking is confirmed then true":{"main":[[{"node":"Information to be Saved in Airtable","type":"main","index":0}]]},"Checks if required info is provided for cancelation":{"main":[[{"node":"Finds the appointment record","type":"main","index":0}],[{"node":"Build Error Response","type":"main","index":0}]]}}}


name: Smart Sales Support Chatbot with GPT-4o and Google Sheets
author_name: Babish Shrestha
author_username: bbz
categories: []
created_at: 2025-04-04T09:13:57.734Z
updated_at: 2025-04-04T09:13:57.734Z
url: https://n8n.io/workflows/3433
scraped_at: 2025-06-19 22:50:30
description:
  Who is this tempate for?
  This workflow powers a simple yet effective customer and sales support chatbot for your webshop. It's perfect for solopreneurs who want to automate customer interactions without relying on expensive or complex support tools.

  How it works?
  The chatbot listens to user requests—such as checking product availability—and automatically handles the following

  Fetches product information from a Google Sheet
  Answers customer queries
  Places an order
  Updates the stock after a successful purchase

  Everything runs through a single Google Sheet used for both stock tracking and order management.

  Setup Instructions

  Before you begin, connect your Google Sheets credentials by following this guide: This will be used to connect all the tools to Google Sheets
  👉 Setup Google sheets credentials

  Get Stock

  	Open "Get Stock" tool node and select the Google sheet credentials you created. 
  	Choose the correct google sheet document and sheet name and you are done.
  Place order
  	
  	Go to your "Place Order" tool node and select the Google sheet credentials you have created. 
  	Choose the correct google sheet document and sheet name.

  Update Stock
  	- Open your "Update Stock" tool node and select the Google sheet credentials you have created. 
  	Choose the correct google sheet document and sheet name.
  	In "Mapping Column Mode" section select map each column manually.
  	In "Column to match on" select the column with a unique identifier (e.g., Product ID) to match stock items.
  	In values to update section, add only the column(s) that need to be updated—usually the stock count.
  AI Agent node 
  	Adjust the prompt according to your use case and customize what you need. 

  Google Sheet Template
  Stock sheet

  |Case ID|Phone Model|Case Name|Case Type|Image URL|Quantity Avaialble|Initital Inventory|Sold|
  |-|-|-|-|-|-|-|-|
  |1023|Iphone 14 pro|Black Leather|Magsafe|https://example.com/url|90|100|10

  Order sheet

  |Case ID|Phone Model|Case Name|Name|Phone Number|Address|
  |-|-|-|-|-|-|
  |1023|Black Leather |Iphone 14 pro|Fernando Torres|9998898888|Paris, France

nodes_used:
[cell repeats an earlier one in this file: 120 characters]

workflow_json:
  {"id":"7Pw91QNT4UGeNmL5","meta":{"instanceId":"95959af22bc98ea4ce12f3aa06514276ddf020a37e9465025051938d10308902","templateCredsSetupCompleted":true},"name":"Customer and Sales Support","tags":[],"nodes":[{"id":"99d711a1-2341-493b-ba56-e40e76e07d97","name":"When chat message received","type":"@n8n/n8n-nodes-langchain.chatTrigger","position":[-360,-120],"webhookId":"1de1a4dd-cea5-4c95-b489-6004601ff727","parameters":{"public":true,"options":{"responseMode":"lastNode","loadPreviousSession":"memory"},"initialMessages":"Hi! I’m Babish from Apple Case. How can I help?”"},"typeVersion":1.1},{"id":"ab809cbb-0456-4a6f-b078-8a6f7bdbd4d0","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[60,260],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4.1","cachedResultName":"gpt-4.1"},"options":{"maxTokens":1024,"temperature":0.3}},"credentials":{"openAiApi":{"id":"zqONgMf7CM0LERga","name":"OpenAi DPL 2"}},"typeVersion":1.2},{"id":"e74bc18b-3058-4658-83fd-85f9a45d3537","name":"Simple Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[-220,240],"parameters":{},"typeVersion":1.3},{"id":"008d806b-e56d-4c37-b64d-2eb6792eefb5","name":"Place order","type":"n8n-nodes-base.googleSheetsTool","position":[540,240],"parameters":{"columns":{"value":{"Address":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Address', ``, 'string') }}","Case ID":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Case_ID', ``, 'string') }}","Quantity":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Quantity', ``, 'string') }}","Case Name":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Case_Name', ``, 'string') }}","Timestamp":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Timestamp', ``, 'string') }}","Phone Model":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Phone_Model', ``, 'string') }}","Phone Number":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Phone_Number', ``, 'string') }}","Customer Name":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Customer_Name', ``, 'string') }}"},"schema":[{"id":"Timestamp","type":"string","display":true,"removed":false,"required":false,"displayName":"Timestamp","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Case ID","type":"string","display":true,"required":false,"displayName":"Case ID","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Case Name","type":"string","display":true,"required":false,"displayName":"Case Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Phone Model","type":"string","display":true,"required":false,"displayName":"Phone Model","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Customer Name","type":"string","display":true,"removed":false,"required":false,"displayName":"Customer Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Phone Number","type":"string","display":true,"required":false,"displayName":"Phone Number","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Address","type":"string","display":true,"removed":false,"required":false,"displayName":"Address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Quantity","type":"string","display":true,"removed":false,"required":false,"displayName":"Quantity","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":622166849,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1btXGPudVDrG64coe5mIlw0Nd8r6YzOnNQ3wp7OVUffc/edit#gid=622166849","cachedResultName":"Order placed"},"documentId":{"__rl":true,"mode":"list","value":"1btXGPudVDrG64coe5mIlw0Nd8r6YzOnNQ3wp7OVUffc","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1btXGPudVDrG64coe5mIlw0Nd8r6YzOnNQ3wp7OVUffc/edit?usp=drivesdk","cachedResultName":"Apple Case Stock"}},"credentials":{"googleSheetsOAuth2Api":{"id":"r16nFPNT77oA4BPq","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"9f1d892a-ad76-47ce-815f-1a7cc7a46cf8","name":"Update Stock","type":"n8n-nodes-base.googleSheetsTool","position":[660,240],"parameters":{"columns":{"value":{"Sold":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Sold', ``, 'string') }}","Case ID":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Case_ID__using_to_match_', ``, 'string') }}","Updated ISO":"={{ $now.toISO() }}","Quantity Available":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Quantity_Available', ``, 'string') }}"},"schema":[{"id":"Case ID","type":"string","display":true,"removed":false,"required":false,"displayName":"Case ID","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Phone Model","type":"string","display":true,"removed":true,"required":false,"displayName":"Phone Model","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Case Name","type":"string","display":true,"removed":true,"required":false,"displayName":"Case Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Case Type","type":"string","display":true,"removed":true,"required":false,"displayName":"Case Type","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Quantity Available","type":"string","display":true,"removed":false,"required":false,"displayName":"Quantity Available","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Initial Inventory,","type":"string","display":true,"removed":true,"required":false,"displayName":"Initial Inventory,","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Sold","type":"string","display":true,"removed":false,"required":false,"displayName":"Sold","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Updated ISO","type":"string","display":true,"removed":false,"required":false,"displayName":"Updated ISO","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["Case ID"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":2019723207,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1btXGPudVDrG64coe5mIlw0Nd8r6YzOnNQ3wp7OVUffc/edit#gid=2019723207","cachedResultName":"Inventory"},"documentId":{"__rl":true,"mode":"list","value":"1btXGPudVDrG64coe5mIlw0Nd8r6YzOnNQ3wp7OVUffc","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1btXGPudVDrG64coe5mIlw0Nd8r6YzOnNQ3wp7OVUffc/edit?usp=drivesdk","cachedResultName":"Apple Case Stock"}},"credentials":{"googleSheetsOAuth2Api":{"id":"r16nFPNT77oA4BPq","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"7f0e6e31-6bdb-4901-9c07-4fb6fa4734f0","name":"Support Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[120,-120],"parameters":{"options":{"systemMessage":"=SYSTEM\nYou are the customer-support agent for “My Apple Case”.\n\nTOOLS\n• GetStock      { \"phone_model\": string }\n  • Returns: [{ \"case_id\": int, \"case_name\": string,\n                \"quantity_available\": int, \"sold\": int,\n                \"image_url\": string, ... }]\n• PlaceOrder    { \"case_id\": int,\n                  \"case_name\": string,\n                  \"phone_model\": string,\n                  \"customer_name\": string,\n                  \"phone_number\": string,\n                  \"address\": string,\n                  \"quantity\": int }\n• UpdateStock   { \"case_id\": int,\n                  \"quantity_sold\": int,\n                  \"quantity_available\": int,\n                  \"sold\": int }\n•  The \"case_id\" you send to PlaceOrder or UpdateStock must be the one that\n   appears **in the same row as the chosen case_name** from the latest\n   GetStock response. Do not invent or modify it.\nRULES\n1. Begin every user-visible reply with:  **Welcome to My Apple Case.**\n2. Speak English or Roman-Nepali, matching the customer.\n3. ONE tool call per turn. \n4. If GetStock returns an **image_url**, embed it after the text line using\n   Markdown:  \n   `![<case_name>](<image_url>)`\n5. Legal case_ids set\n   • The only valid case_id values are the ones you just received from\n     GetStock in this conversation turn.\n6. Guard clause\n   • If you do not have a valid case_id for the customer’s chosen case,\n     ask follow-up questions or run GetStock again.  DO NOT guess.\n7.Picking the correct case_id\n   a. After GetStock returns, keep its rows in memory.\n   b. When the customer names a case_name you just showed, locate the row\n      whose case_name matches **exactly** (case-insensitive) and copy that\n      row’s case_id.\n   c. If more than one row shares the same case_name, ask which “Option #”\n      or show a numbered list so they can pick.  Never guess.\n\nWORKFLOW\na. If you don’t yet know stock data, call **GetStock** with the phone model.  \nb. From GetStock output read:\n      qa = quantity_available\n      sold = sold\n      img  = image_url  \n  • Show the case_id, case_name, qa and (if img exists) the image. \nc. If qa < requested quantity → apologize, no PlaceOrder. \nd. Determine the correct case_id:\n     • EXACT match: one row → use that row’s case_id.\n     • Multiple matches: show a numbered list and ask the customer to\n       choose (e.g. “Type 1 or 2”).  Run no tools until they choose.\n   Then call PlaceOrder using that exact case_id.\ne. Else collect missing customer fields → call **PlaceOrder**.  \nf. After PlaceOrder succeeds, compute:\n      qa_new   = qa   - quantity\n      sold_new = sold + quantity\n   then call **UpdateStock** with:\n      { \"case_id\": ..., \"quantity_sold\": quantity,\n        \"quantity_available\": qa_new, \"sold\": sold_new }\ng. After UpdateStock returns, thank the customer and show qa_new.\n\nEXAMPLES\n### Check stock with image\nUser: iPhone 12 ko cover cha?  \nAssistant → tool:  \n{ \"tool\": \"GetStock\", \"args\": { \"phone_model\": \"iPhone 12\" } }\n\n(GetStock output example)  \n[\n  {\n    \"case_id\": 312,\n    \"case_name\": \"Clear MagSafe Case\",\n    \"quantity_available\": 25,\n    \"sold\": 75,\n    \"image_url\": \"https://example.com/clear-case.png\"\n  }\n]\n\n### Two rows same name\n(GetStock output)\n1. case_id 101  \"Leather Flip\"  qty 3\n2. case_id 202  \"Leather Flip\"  qty 10\n\nUser: I want the Leather Flip case.\nAssistant: Welcome to My Apple Case. I have two “Leather Flip” options:\n(1) case_id 101 – 3 in stock\n(2) case_id 202 – 10 in stock\nWhich one would you like? Please reply 1 or 2.\n\nMy Apple Case ma swagatam. **Clear MagSafe Case** – 25 stock cha.  \n![Clear MagSafe Case](https://example.com/clear-case.png)\n","returnIntermediateSteps":true}},"retryOnFail":true,"typeVersion":1.8},{"id":"03153a59-4971-49db-86c2-5fd245b36d28","name":"GetStock","type":"n8n-nodes-base.googleSheetsTool","position":[400,240],"parameters":{"options":{},"filtersUI":{"values":[{"lookupValue":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Value', ``, 'string') }}","lookupColumn":"Phone Model"}]},"sheetName":{"__rl":true,"mode":"list","value":2019723207,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1btXGPudVDrG64coe5mIlw0Nd8r6YzOnNQ3wp7OVUffc/edit#gid=2019723207","cachedResultName":"Inventory"},"documentId":{"__rl":true,"mode":"list","value":"1btXGPudVDrG64coe5mIlw0Nd8r6YzOnNQ3wp7OVUffc","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1btXGPudVDrG64coe5mIlw0Nd8r6YzOnNQ3wp7OVUffc/edit?usp=drivesdk","cachedResultName":"Apple Case Stock"},"combineFilters":"OR"},"credentials":{"googleSheetsOAuth2Api":{"id":"r16nFPNT77oA4BPq","name":"Google Sheets account"}},"typeVersion":4.5}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"6f49665c-583f-456e-9ea9-bb95b172cac1","connections":{"GetStock":{"ai_tool":[[{"node":"Support Agent","type":"ai_tool","index":0}]]},"Place order":{"ai_tool":[[{"node":"Support Agent","type":"ai_tool","index":0}]]},"Update Stock":{"ai_tool":[[{"node":"Support Agent","type":"ai_tool","index":0}]]},"Simple Memory":{"ai_memory":[[{"node":"Support Agent","type":"ai_memory","index":0},{"node":"When chat message received","type":"ai_memory","index":0}]]},"Support Agent":{"main":[[]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Support Agent","type":"ai_languageModel","index":0}]]},"When chat message received":{"main":[[{"node":"Support Agent","type":"main","index":0}]]}}}


name: Get Qualified Leads in One Click from Apollo to Airtable
author_name: Not Another Marketer
author_username: notanothermarketer
nodes_used: ["n8n-nodes-base.airtable","n8n-nodes-base.httpRequest"]
categories: []
created_at: 2025-04-04T11:10:06.804Z
updated_at: 2025-04-04T11:10:06.804Z
url: https://n8n.io/workflows/3435
scraped_at: 2025-06-19 22:50:31
description:
  You Don’t Need More Tools. You Just Need the Right Leads.
  Why spend $1,000s on lead gen when your perfect leads are already waiting in Apollo? You’ve already filtered the ideal prospects. You know who they are, where they work, and what they do.

  Now imagine turning that list into enriched, ready-to-contact leads—without paying pricey Apollo's recurring subscription (spoiler: you will pay only 0.60$ per 500 leads).

  From Filter to Outreach-Ready in Seconds
  With the Lead Generation System, you just drop your Apollo search URL.

  The workflow does the rest:
  ✅ Scrapes all matching contacts from your Apollo filter
  ✅ Enriches and organizes the data (names, roles, emails, LinkedIns, companies, etc.)
  ✅ Delivers the final lead list to Airtable—or your CRM of choice

  No more manual exports. 
  No CSV mess. 
  No VA needed.
  Just qualified leads, cleaned and ready to go.

  Perfect For
  Founders doing DIY outbound
  Growth marketers scaling cold email
  Agencies running lead-gen for clients
  Anyone tired of paying too much for messy, outdated lists

  Setup Guide
  I built a step-by-step guide to setup this workflow in 5 to 10 minutes, available here: https://notanothermarketer.gitbook.io/home/templates/lead-generation

  This template is free. Enjoy!

workflow_json:
  {"id":"EWIrJ8e9z7AijmTu","meta":{"instanceId":"e8ec316b54e91908f34cbfdc330e5d1d5e97aa0ea8f7277c00d8a8a3892c9983","templateCredsSetupCompleted":true},"name":"Lead Generation System (Template)","tags":[],"nodes":[{"id":"03eabaeb-ad13-4764-98de-183325e32cbd","name":"When clicking ‘Test workflow’","type":"n8n-nodes-base.manualTrigger","position":[160,-80],"parameters":{},"typeVersion":1},{"id":"e7df072c-fba8-4dc2-94ce-ae20a135a633","name":"Edit Fields","type":"n8n-nodes-base.set","position":[840,-80],"parameters":{"options":{},"assignments":{"assignments":[{"id":"ab7e33d5-986e-4fba-b4d0-bc47bcd1cf82","name":"first_name","type":"string","value":"={{ $json.first_name }}"},{"id":"f29e8cf7-3cd0-4ffc-a071-96be9dd1da50","name":"last_name","type":"string","value":"={{ $json.last_name }}"},{"id":"54ee5cec-ccaf-4f34-8030-d17206abef5d","name":"email","type":"string","value":"={{ $json.email }}"},{"id":"daf1fa7c-a7fc-4b96-8184-a5569b9ab9a0","name":"email_status","type":"string","value":"={{ $json.email_status }}"},{"id":"2c7e31e5-42a2-4295-ae8b-108d8a7d409a","name":"linkedin_url","type":"string","value":"={{ $json.linkedin_url }}"},{"id":"4002f912-0581-4219-8443-96c13133dc76","name":"headline","type":"string","value":"={{ $json.headline }}"},{"id":"fa92887f-fff5-4ee4-9b80-05115b83f718","name":"organization","type":"string","value":"={{ $json.organization_name }}"},{"id":"c274e875-6a53-484a-87b1-3c672101603f","name":"organization_website","type":"string","value":"={{ $json.organization_website_url }}"},{"id":"af6208a2-d064-471b-a417-7d96e9d05803","name":"organization_linkedin_url","type":"string","value":"={{ $json.organization_linkedin_url }}"},{"id":"d61f2ddb-4c50-4548-8a7f-08261c60c429","name":"current_job_title","type":"string","value":"={{ $json.title }}"},{"id":"838c77f2-618e-43b2-9df6-e5e1bde39105","name":"country","type":"string","value":"={{ $json.country }}"},{"id":"9dc784cf-ae01-44e3-afed-16a95192bf71","name":"city","type":"string","value":"={{ $json.city }}"}]}},"typeVersion":3.4},{"id":"3aaa9ea7-0c5d-4ea3-aa10-6cd0125ea91a","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[80,-280],"parameters":{"color":5,"width":1200,"height":520,"content":"## Lead Generation\nGet thousands of enriched leads in seconds."},"typeVersion":1},{"id":"42e3f6de-4ec4-46a7-a7f9-c028d27a677b","name":"Scrape Leads","type":"n8n-nodes-base.httpRequest","position":[380,-80],"parameters":{"url":"=","options":{},"jsonBody":"{\n    \"getPersonalEmails\": true,\n    \"getWorkEmails\": true,\n    \"totalRecords\": 500,\n    \"url\": \"\"\n}","sendBody":true,"specifyBody":"json"},"typeVersion":4.2},{"id":"dfd580f6-99b5-414a-b6f3-77c73edc85ec","name":"Save Leads in database","type":"n8n-nodes-base.airtable","position":[1040,-80],"parameters":{"base":{"__rl":true,"mode":"list","value":"appy1hlfTk0UuYwRb","cachedResultUrl":"https://airtable.com/appy1hlfTk0UuYwRb","cachedResultName":"Lead Gen - Mastersheet"},"table":{"__rl":true,"mode":"list","value":"tbl0rwfpUYkqMiysR","cachedResultUrl":"https://airtable.com/appy1hlfTk0UuYwRb/tbl0rwfpUYkqMiysR","cachedResultName":"Leads"},"columns":{"value":{"city":"={{ $json.city }}","country":"={{ $json.country }}","headline":"={{ $json.headline }}","last_name":"={{ $json.last_name }}","first_name":"={{ $json.first_name }}","email_status":"={{ $json.email_status }}","linkedin_url":"={{ $json.linkedin_url }}","email_address":"={{ $json.email }}","current_job_title":"={{ $json.current_job_title }}","organization_name":"={{ $json.organization }}","organization_website":"={{ $json.organization_website }}","organization_linkedin_url":"={{ $json.organization_linkedin_url }}"},"schema":[{"id":"email_address","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"first_name","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"first_name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"last_name","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"last_name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"headline","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"headline","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"organization_name","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"organization_name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"organization_website","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"organization_website","defaultMatch":false,"canBeUsedToMatch":true},{"id":"organization_linkedin_url","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"organization_linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"current_job_title","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"current_job_title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"country","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"country","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_status","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"email_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"city","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"city","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"create"},"credentials":{"airtableTokenApi":{"id":"WKxw33bpSEDiQEaU","name":"Airtable Personal Access Token account"}},"typeVersion":2.1},{"id":"ff009ef3-c7da-460a-80e5-ba1330631c00","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-400,-280],"parameters":{"color":3,"width":460,"height":180,"content":"## 🚨 readMeFirst 🚨\nThis template is built by [Not Another Marketer](https://notanothermarketer.com)\n\nStep-by-step setup guide: https://notanothermarketer.gitbook.io/\n\nAny questions? [Reach out on X](https://x.com/notanothermrktr) "},"typeVersion":1},{"id":"0915cea5-746a-4dde-9208-885e08644ae2","name":"Filter leads without email","type":"n8n-nodes-base.if","position":[600,-80],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"231ec40a-bd12-46e2-ab6b-a8c4d6728983","operator":{"type":"string","operation":"exists","singleValue":true},"leftValue":"={{ $json.email }}","rightValue":""}]}},"typeVersion":2.2}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"f574ed33-bd0a-496b-865e-e6be2c1e3060","connections":{"Edit Fields":{"main":[[{"node":"Save Leads in database","type":"main","index":0}]]},"Scrape Leads":{"main":[[{"node":"Filter leads without email","type":"main","index":0}]]},"Filter leads without email":{"main":[[{"node":"Edit Fields","type":"main","index":0}]]},"When clicking ‘Test workflow’":{"main":[[{"node":"Scrape Leads","type":"main","index":0}]]}}}


name: Fully Automated AI Video Generation & Multi-Platform Publishing
author_name: Juan Carlos Cavero Gracia
author_username: carlosgracia
categories: []
created_at: 2025-04-05T18:28:46.255Z
updated_at: 2025-04-05T18:28:46.255Z
url: https://n8n.io/workflows/3442
scraped_at: 2025-06-19 22:48:45
description:
  Description

  This comprehensive n8n automation template orchestrates a complete end-to-end workflow for generating engaging short-form Point-of-View (POV) style videos using multiple AI services and automatically publishing them across major social media platforms. It takes ideas from a Google Sheet and transforms them into finished videos with captions, voiceovers, and platform-specific descriptions, ready for distribution.

  Who Is This For?

  Content Creators & Agencies:** Mass-produce unique short-form video content for various clients or channels with minimal manual effort.
  Digital Marketers:** Automate video content pipelines to boost online presence and engagement across multiple platforms simultaneously.
  Social Media Managers:** Schedule and distribute consistent video content efficiently without juggling multiple tools and manual uploads.
  Businesses:** Leverage AI to create branded video content for marketing, reducing production time and costs.

  What Problem Does This Workflow Solve?

  Creating and distributing high-quality short-form video content consistently across multiple social networks is incredibly time-consuming and resource-intensive. This workflow tackles these challenges by:

  Automating Idea-to-Video Pipeline:** Generates video concepts, image prompts, scripts, images, video clips, and voiceovers using AI.
  Streamlining Video Assembly:** Automatically combines generated assets into a final video using a template.
  Generating Platform-Optimized Descriptions:** Creates relevant descriptions for posts by transcribing the final video audio.
  Automating Multi-Platform Publishing:** Uploads the final video and description to TikTok, Instagram, YouTube, Facebook, and LinkedIn simultaneously.
  Reducing Manual Workload:** Drastically cuts down the time and effort required for video production and distribution.
  Centralized Tracking:** Updates a Google Sheet with results, costs, and status for easy monitoring.

  How It Works

  Trigger & Input: Runs on a daily schedule (configurable) and fetches new video ideas from a designated Google Sheet.
  AI Content Generation:
      Uses OpenAI to generate video captions and image prompts based on the idea.
      Uses PiAPI (Flux) to generate images from prompts.
      Uses PiAPI (Kling) to generate video clips from the images (Image-to-Video).
      Uses OpenAI to generate a voiceover script based on the captions.
      Uses ElevenLabs to generate voiceover audio from the script and uploads it to Google Drive.
  Video Assembly: Combines the generated video clips, captions, and voiceover audio using a Creatomate template to render the final video.
  Description Generation: Uploads the final video to Google Drive, extracts the audio using OpenAI (Whisper), and generates a social media description using OpenAI (GPT).
  Multi-Platform Distribution: Uses upload-post.com to upload the final video and generated description to TikTok, Instagram, YouTube, Facebook, and LinkedIn.
  Tracking & Notification: Updates the original Google Sheet row with output details (video link, costs, tokens used) and sends a completion notification via Discord.

  Setup

  Accounts & API Keys: Obtain accounts and generate API keys/credentials for:
      n8n
      Google Cloud Platform (for Google Sheets & Google Drive APIs + OAuth Credentials)
      OpenAI
      PiAPI
      ElevenLabs
      Creatomate
      upload-post.com
      Discord (Webhook URL)
  Google Sheet: Make a copy of the provided Google Sheet Template and connect it in the Load Google Sheet node.
  Creatomate Template: Set up a video template in Creatomate (use the provided JSON source code as a base) and note its Template ID.
  Configure Nodes:
      Enter all API Keys/Credentials in the Set API Keys node and other relevant credential sections (Google nodes, upload-post nodes, etc.).
      Configure Google Drive nodes (Folder IDs, Permissions).
      Configure the upload-post.com nodes with your user identifier and necessary platform details (e.g., Facebook Page ID).
      Customize AI prompts within the OpenAI nodes (Generate Video Captions, Generate Image Prompts, Generate Script, Generate Description...) if desired.
      Set the Discord Webhook URL in the Notify me on Discord node.
  Enable Google APIs: Ensure Google Drive API and Google Sheets API are enabled in your Google Cloud Project.

  Requirements

  Accounts:** n8n, Google (Sheets, Drive, Cloud Platform), OpenAI, PiAPI, ElevenLabs, Creatomate, upload-post.com, Discord.
  API Keys & Credentials:** API Keys for OpenAI, PiAPI, ElevenLabs, Creatomate, upload-post.com. Google Cloud OAuth 2.0 Credentials. Discord Webhook URL.
  Templates:** A configured Google Sheet based on the template, a configured Creatomate video template.
  (Potentially) Paid Plans:** Some services (OpenAI, PiAPI, Creatomate, upload-post.com) may require paid plans depending on usage volume after free trials/credits are exhausted.

  Use this template to build a powerful, automated video content factory, scaling your production and distribution efforts across the social media landscape.

nodes_used:
  ["n8n-nodes-base.googleSheets","n8n-nodes-base.httpRequest","n8n-nodes-base.googleDrive","n8n-nodes-base.discord","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.openAi"]

workflow_json:
  {"id":"KY0vB3hifSrA24k2","meta":{"instanceId":"3378b0d68c3b7ebfc71b79896d94e1a044dec38e99a1160aed4e9c323910fbe2","templateId":"3121"},"name":"AI-Powered Short-Form Video Generator with OpenAI, Flux, Kling, and ElevenLabs and upload to all social networks","tags":[],"nodes":[{"id":"e5095169-dc78-4d90-9662-04cfc82c38d9","name":"Get image","type":"n8n-nodes-base.httpRequest","position":[1160,480],"parameters":{"url":"=https://api.piapi.ai/api/v1/task/{{ $json.data.task_id }}","options":{},"sendHeaders":true,"headerParameters":{"parameters":[{"name":"X-API-Key","value":"={{ $('Set API Keys').item.json['PiAPI Key'] }}"}]}},"typeVersion":4.2},{"id":"f477250a-fc8e-407e-a632-cffc0e564596","name":"Generate Image","type":"n8n-nodes-base.httpRequest","position":[880,480],"parameters":{"url":"https://api.piapi.ai/api/v1/task","body":"={\n  \"model\": \"Qubico/flux1-dev\",\n  \"task_type\": \"txt2img\",\n  \"input\": {\n    \"prompt\": \"{{ $('Generate Image Prompts').item.json.choices[0].message.content }} realistic and casual as if taken by an iphone camera by a TikTok influencer\",\n    \"negative_prompt\": \"taking a photo of a room, recording a video of a room, photos app, video recorder, illegible text, blurry text, low quality text, DSLR, unnatural\",\n    \"width\": 540,\n    \"height\": 960\n  }\n}","method":"POST","options":{},"sendBody":true,"contentType":"raw","sendHeaders":true,"rawContentType":"application/json","headerParameters":{"parameters":[{"name":"X-API-Key","value":"={{ $('Set API Keys').item.json['PiAPI Key'] }}"}]}},"retryOnFail":false,"typeVersion":4.2},{"id":"622ce9f5-ad58-485b-a3c6-1265700b04da","name":"Image-to-Video","type":"n8n-nodes-base.httpRequest","position":[520,1000],"parameters":{"url":"https://api.piapi.ai/api/v1/task","body":"={\n  \"model\": \"kling\",\n  \"task_type\": \"video_generation\",\n  \"input\": {\n    \"prompt\": \"{{ $json.data.input.prompt }}\",\n    \"negative_prompt\": \"blurry motion, distorted faces, unnatural lighting, over produced, bad quality\",\n    \"cfg_scale\": 0.5,\n    \"duration\": 5,\n    \"mode\": \"pro\",\n    \"image_url\": \"{{ $json.data.output.image_url }}\",\n    \"version\": \"1.6\",\n    \"camera_control\": {\n      \"type\": \"simple\",\n      \"config\": {\n        \"horizontal\": 0,\n        \"vertical\": 0,\n        \"pan\": 0,\n        \"tilt\": 0,\n        \"roll\": 0,\n        \"zoom\": 5\n      }\n    }\n  },\n  \"config\": {}\n}","method":"POST","options":{},"sendBody":true,"contentType":"raw","sendHeaders":true,"rawContentType":"application/json","headerParameters":{"parameters":[{"name":"X-API-Key","value":"={{ $('Set API Keys').item.json['PiAPI Key'] }}"}]}},"typeVersion":4.2},{"id":"ed14eac3-1d63-481d-871c-a04c52977fc6","name":"Get Video","type":"n8n-nodes-base.httpRequest","position":[780,1000],"parameters":{"url":"=https://api.piapi.ai/api/v1/task/{{ $json.data.task_id }}","options":{},"sendHeaders":true,"headerParameters":{"parameters":[{"name":"X-API-Key","value":"={{ $('Set API Keys').item.json['PiAPI Key'] }}"}]}},"typeVersion":4.2},{"id":"8b68100c-8a5a-405c-825e-d9e8a898f235","name":"List Elements","type":"n8n-nodes-base.code","position":[1400,1040],"parameters":{"jsCode":"return [\n  {\n    scene_titles: items.map(item => item.json.response.text),\n    video_urls: items.map(item => item.json.data.output.video_url),\n    input_tokens: $('Calculate Token Usage').first().json.total_prompt_tokens,\n    output_tokens: $('Calculate Token Usage').first().json.total_completion_tokens,\n    model: $('Generate Image Prompts').first().json.model\n  }\n];"},"typeVersion":2},{"id":"f8780885-508e-4dc9-b146-f367297d7b68","name":"Wait 10min","type":"n8n-nodes-base.wait","position":[660,1000],"webhookId":"1f9d716f-6544-4e4e-94ec-408ac3ea6e82","parameters":{"unit":"minutes","amount":10},"typeVersion":1.1},{"id":"6290bc91-0eb9-4053-bd93-961cb9e917c0","name":"Wait 3min","type":"n8n-nodes-base.wait","position":[1020,480],"webhookId":"77cdee73-5e99-456a-b5e7-410b4d257669","parameters":{"unit":"minutes","amount":3},"typeVersion":1.1},{"id":"818a66ef-b9fa-4efc-85d1-b295300cbed8","name":"Wait 5min","type":"n8n-nodes-base.wait","position":[1480,400],"webhookId":"31d5b1a2-dbb5-4849-ae25-cb491539c16e","parameters":{"unit":"minutes"},"typeVersion":1.1},{"id":"afd66320-dfe0-4872-a09d-d53fe08152ce","name":"Generate voice","type":"n8n-nodes-base.httpRequest","position":[880,1460],"parameters":{"url":"https://api.elevenlabs.io/v1/text-to-speech/onwK4e9ZLuTAKqWW03F9","method":"POST","options":{},"sendBody":true,"sendHeaders":true,"bodyParameters":{"parameters":[{"name":"text","value":"={{ $json.choices[0].message.content }}"}]},"headerParameters":{"parameters":[{"name":"xi-api-key","value":"={{ $('Set API Keys').item.json['ElevenLabs API Key'] }}"}]}},"retryOnFail":false,"typeVersion":4.2},{"id":"916f19e1-7928-4141-a5c5-ca39bd22b0a0","name":"List Elements1","type":"n8n-nodes-base.code","position":[1400,1260],"parameters":{"jsCode":"return [\n  {\n    sound_urls: items.map(item => $('Upload Voice Audio').first().json.webContentLink)\n  }\n];"},"typeVersion":2},{"id":"b95fd80c-ec7f-4d50-99ae-f3f544b8a111","name":"Fail check","type":"n8n-nodes-base.if","position":[920,1000],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"a920eb54-fc23-4b68-8f56-2eee907a5481","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.data.status }}","rightValue":"failed"}]}},"typeVersion":2.2},{"id":"7e3f5cda-1d49-4a59-956f-f639daf203e0","name":"Wait to retry","type":"n8n-nodes-base.wait","position":[1060,960],"webhookId":"3b0fae8f-4419-45cd-8380-8f72eca05ff8","parameters":{"unit":"minutes"},"typeVersion":1.1},{"id":"48ec39c9-1802-4860-918d-9c660051f27b","name":"Generate Image Prompts","type":"@n8n/n8n-nodes-langchain.openAi","position":[400,560],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"o3-mini","cachedResultName":"O3-MINI"},"options":{},"messages":{"values":[{"content":"=You are an advanced, unhinged, hilariously entertaining prompt-generation AI specializing in expanding short POV image prompt ideas into detailed, hyper-realistic prompts optimized for Qubico/flux1-dev. Your task is to take a brief input tied to job seeking, job hunting, or resume building and morph it into a cinematic, immersive prompt locked in a first-person perspective, making the viewer feel they’re living the scene.\n\nNEVER include quotation marks or emojis in your response—flux API will choke on them, and that’s a hard no.\n\nThe topic of this narrative is: {{ $('Load Google Sheet').item.json.idea }}\n\nThe short prompt idea to expand for this image generation is: {{ $json.response.text }}\n\nONLY GENERATE ONE PROMPT PER IDEA—NO COMBINING. In at least one scene, weave in this environment descriptor: {{ $('Load Google Sheet').first().json.environment_prompt }}, but go wild with unhinged, edgy, funny twists elsewhere (skip the cringe or cheesy garbage). Most job hunting happens on laptops or desktops, so prioritize those over phones. If a phone sneaks in, it’s only showing job-related content like email, LinkedIn, a resume, or a job posting—never a photo or video app.\n\nEvery prompt has two parts:\n\nForeground: Kick off with First person view POV GoPro shot of... and show the viewer’s hands, limbs, or feet locked in a job-related action.\n\nBackground: Start with In the background,... and paint the scenery, blending the environment descriptor when required, plus sensory zingers.\n\nTop Rules:\n\nNO quotation marks or emojis—EVER. This is life or death for flux.\nStick to first-person POV—the viewer’s in the driver’s seat, not watching from the sidelines.\nShow a limb (hands, feet) doing something job-focused—typing, holding a resume, adjusting a tie.\nKeep it dynamic, like a GoPro clip, with motion and depth mimicking human vision.\nIf tech’s involved (phone, computer), it’s displaying job-hunting gold—email, job boards, resumes—not random trash.\nNo off-topic actions like recording videos or snapping pics—job hunting only, fam.\nExtra Vibes:\n\nFull-body awareness: Drop hints of physical feels—cramping fingers, racing pulse, slumping shoulders.\nSensory overload: Hit sight, touch, sound, smell, temperature for max realism (coffee whiffs, keyboard clacks).\nWorld grip: Limbs interact with the scene—tapping keys, handing over papers, stepping up.\nKeep it under 1000 characters, one slick sentence, no fluff or formatting.\nMake it entertaining, relatable, with an Andrew Tate viral edge for the down-and-out job hustlers.\nExamples:\n\nInput: Updating a LinkedIn profile after a long day\n\nEnvironment_prompt: Tired, cluttered apartment, laptop glow\n\nOutput: First person view POV GoPro shot of my hands hammering a laptop, cheeto-dusted fingers aching from the grind, the screen flashing my LinkedIn profile with a fresh connection ping; in the background, a trashed apartment lit by the laptop’s ghostly glow, pizza boxes toppling, traffic humming outside, stale takeout stench hitting my nose as my back screams from the hustle.\n\nInput: Handing over a resume at a job fair\n\nEnvironment_prompt: Hopeful, busy convention hall, suits everywhere\n\nOutput: First person view POV GoPro shot of my hand thrusting out a crisp resume, fingers twitching with nerves as it brushes another palm; in the background, a buzzing convention hall packed with suits, coffee fumes and shoe polish in the air, chatter drowning my pounding heart as I lock eyes with the recruiter.\n\nNO QUOTATION MARKS. NO EMOJIS. EVER."}]},"simplify":false},"typeVersion":1.8},{"id":"5c1b8dc8-4eb3-49fe-81c7-c811d73fac0d","name":"Calculate Token Usage","type":"n8n-nodes-base.code","position":[700,560],"parameters":{"jsCode":"// Get all input items (the 5 LLM responses)\nconst items = $input.all();\n\n// Calculate total prompt tokens and total completion tokens\nconst totalPromptTokens = items.reduce((sum, item) => sum + item.json.usage.prompt_tokens, 0);\nconst totalCompletionTokens = items.reduce((sum, item) => sum + item.json.usage.completion_tokens, 0);\n\n// Create new items with original data plus the totals\nconst outputItems = items.map(item => ({\n  json: {\n    ...item.json,                   // Spread the original item data\n    total_prompt_tokens: totalPromptTokens,     // Add total prompt tokens\n    total_completion_tokens: totalCompletionTokens // Add total completion tokens\n  }\n}));\n\n// Return the modified items\nreturn outputItems;"},"typeVersion":2},{"id":"efc3d0dd-70dc-4fba-b040-22c773ed5602","name":"Check for failures","type":"n8n-nodes-base.if","position":[1300,480],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"567d1fc9-0638-4a44-b5f5-30a9a6683794","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.data.status }}","rightValue":"failed"}]}},"typeVersion":2.2},{"id":"3161c993-5696-4419-9299-fde51719dfc7","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[380,240],"parameters":{"color":5,"width":1260,"height":460,"content":"## 2. 🖼️Generate images with Flux using [PiAPI](https://piapi.ai/?via=n8n) \n### (total cost: $0.0948 approx. as of 3/9/25)\n1. OpenAI is used to generate 5 Flux image prompts based on the 5 captions generated. Edit this node to see/edit the prompt instructions. \n2. Next we use some custom javascript to total up how many tokens were used for each 5 generations so we can track our costs later.\n3. Then we generate an image with Flux using the [PiAPI service](https://piapi.ai/?via=n8n), waiting to check for failures and retrying if there are any.\n\nYou can change the image model used by editing the Generate Image node API call.\nFlux models available (as of 3/9/25):\n- Qubico/flux1-dev ($0.015) - Currently set\n- Qubico/flux1-schnell ($0.0015)\n- Qubico/flux1-advanced ($0.02)\n\nFor full list of API settings, see the [Flux API Documentation](https://piapi.ai/docs/flux-api/text-to-image?via=n8n)\n"},"typeVersion":1},{"id":"e5cdec7e-cb75-4200-a8e3-615621d20150","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[480,720],"parameters":{"color":6,"width":1040,"height":500,"content":"## 3. 🎬Generate videos with Kling using [PiAPI](https://piapi.ai/?via=n8n)\n### (total cost: $2.30 approx. as of 3/9/25)\n1. We use image-to-video with Kling using [PiAPI](https://piapi.ai/?via=n8n) to generate a video from each image.\n2. Then we wait to check for failures, and repeat the generations the failed if there are any.\n\nYou can edit the video model used in the Image-to-Video node. For testing, I'd recommend switching from pro to std for lower quality and cheaper price.\nKling models available (as of 3/9/25):\n- std (Standard) $0.26 per 5 second video\n- pro (Professional) $0.46 per 5 second video - Currently set\n\nFor full list of API settings, see the [Kling API Documentation](https://piapi.ai/docs/kling-api/create-task?via=n8n)\n"},"typeVersion":1},{"id":"8404a390-a402-4703-8cb5-4a54490dc7bd","name":"Generate Video Captions","type":"@n8n/n8n-nodes-langchain.openAi","position":[-40,1220],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"GPT-4O-MINI"},"options":{},"messages":{"values":[{"role":"system","content":"DO NOT include any quotation marks in your response. Do not put a quote at the beginning or the end of your response.\n\nYou are a prompt-generation AI specializing in crafting unhinged, entertaining TikTok captions for a \"day in the life\" POV story about job hunting or resume writing. Generate five concise, action-driven captions (5-10 words each) that follow a Problem > Action > Reward structure. The first caption should be a shocking or funny hook, and the last should conclude with a satisfying reward. Use emojis sparingly—only one per caption at most, and only when they add impact; skip them if they don’t enhance the message.\n\nGuidelines:\n\nPerspective: Always first-person POV, immersing the viewer in the story.\nTone: Channel Andrew Tate mixed with Charlie Sheen—cursing and sexual innuendos are fair game.\nContent: Focus on job seeking, hunting, or resume building, spotlighting AI as the game-changer.\nNarrative: Start with the grind of unemployment or a shitty job, pivot to using AI for resumes and cover letters, and end with scoring the dream gig.\nScenes: Highlight raw, emotional moments—skip the boring stuff.\nYour captions should be wild and entertaining, not polished or professional. The first caption is the hook—make it shocking, hilarious, or ballsy, something Andrew Tate would growl. Use emojis sparingly—max one per caption, only if it hits harder with it.\n\nYour response should be a list of 5 items separated by \"\\n\" (for example: \"item1\\nitem2\\nitem3\\nitem4\\nitem5\")"},{"content":"={{ $json.idea }}"}]},"simplify":false},"typeVersion":1.8},{"id":"f614c784-a3ee-4eb8-aee3-cc0ad3e87556","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[480,1240],"parameters":{"color":4,"width":1040,"height":400,"content":"## 4. 🔉Generate voice overs with [Eleven Labs](https://try.elevenlabs.io/n8n)\n1. OpenAI API is used to generate a funny script that relates to the captions. Open this node to see/edit the prompt instructions. \n2. Then we use the [Eleven Labs API](https://try.elevenlabs.io/n8n) to generate the voiceover and upload it to our Google Drive so it can be accessed in the next step.\n\nTo replace the voice, find the voice ID of the voice you want to use in [Eleven Labs](https://try.elevenlabs.io/n8n), then change the URL in the Generate Voice node to: https://api.elevenlabs.io/v1/text-to-speech/{voice ID here}\n\nFor full list of API settings, see the [Eleven Labs API Documentation](https://elevenlabs.io/docs/api-reference/text-to-speech/convert)\n"},"typeVersion":1},{"id":"e59306c1-8efe-4d98-9391-10c68c17787b","name":"Match captions with videos","type":"n8n-nodes-base.merge","position":[1240,1040],"parameters":{"mode":"combine","options":{},"combineBy":"combineByPosition"},"typeVersion":3},{"id":"8da7e16e-691b-4335-bfc7-e196c36f982d","name":"Generate Script","type":"@n8n/n8n-nodes-langchain.openAi","position":[520,1460],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"GPT-4O-MINI"},"options":{},"messages":{"values":[{"role":"system","content":"=You are an unhinged and hilarious TikTok influencer who's like a mix of Andrew Tate and Charlie Sheen. The user is going to provide you with a topic, and then 5 different parts of a story. Your task is to narrate the story as this hilarious character, who isn't afraid to be edgy or curse or use sexual innuendos. However keep each of the 5 talking points brief, as you only have about 5 seconds to speak during each. The entire length of your narration should be around 15 seconds.\n\nEach line item of the users message represents 1 5 second clip, so your response needs to be able to quickly and easily be spoken in those time constraints. Don't say extra things you don't need to. Just quickly tell the story, in order, and make it unhinged, funny, entertaining, and potentially controversially viral. Don't worry about offendeding anyone. Andrew Tate style it.\n\nDo not include any emojis, as your response will be converted from text to speech, so anything but text and punctuation isn't neccesary. Also, don't make your jokes overly corny, speak in a witty, edgy, funny way, but no corny dad jokes or anything cringe."},{"content":"={{ $('Generate Video Captions').item.json.choices[0].message.content }}"}]},"simplify":false},"executeOnce":true,"typeVersion":1.8},{"id":"ad87317d-3ed0-4fdf-aea5-7b2fa60fb59f","name":"Upload Voice Audio","type":"n8n-nodes-base.googleDrive","position":[1080,1460],"parameters":{"name":"={{ $('Load Google Sheet').item.json.id }}-voiceover.mp3","driveId":{"__rl":true,"mode":"list","value":"My Drive"},"options":{},"folderId":{"__rl":true,"mode":"list","value":"1w1EQ8xyth6w7AbX2wpDI3vInfYeRy8vH","cachedResultUrl":"https://drive.google.com/drive/folders/1w1EQ8xyth6w7AbX2wpDI3vInfYeRy8vH","cachedResultName":"Resume Studio"}},"typeVersion":3},{"id":"eec529e9-2601-4f7b-b415-63d2ebba1574","name":"Set Access Permissions","type":"n8n-nodes-base.googleDrive","position":[1260,1460],"parameters":{"fileId":{"__rl":true,"mode":"id","value":"={{ $json.id }}"},"options":{},"operation":"share","permissionsUi":{"permissionsValues":{"role":"writer","type":"anyone","allowFileDiscovery":true}}},"typeVersion":3},{"id":"63e72d56-140e-47d8-9f72-b58c764deed9","name":"Pair Videos with Audio","type":"n8n-nodes-base.merge","position":[1620,1140],"parameters":{"mode":"combine","options":{},"combineBy":"combineByPosition"},"typeVersion":3},{"id":"60a80c6f-0385-48e6-9b71-c23a74cbc15c","name":"Render Final Video","type":"n8n-nodes-base.httpRequest","position":[1800,1140],"parameters":{"url":"https://api.creatomate.com/v1/renders","body":"={\n  \"template_id\": \"{{ $('Set API Keys').item.json['Creatomate Template ID'] }}\",\n  \"modifications\": {\n    \n    \"Video-1.source\": \"{{ $json.video_urls[0] }}\",\n    \"Video-2.source\": \"{{ $json.video_urls[1] }}\",\n    \"Video-3.source\": \"{{ $json.video_urls[2] }}\",\n    \"Video-4.source\": \"{{ $json.video_urls[3] }}\",\n    \"Video-5.source\": \"{{ $json.video_urls[4] }}\",\n\n    \"Audio-1.source\": \"{{ $json.sound_urls[0] }}\",\n\n    \"Text-1.text\": \"{{ $json.scene_titles[0] }}\",\n    \"Text-2.text\": \"{{ $json.scene_titles[1] }}\",\n    \"Text-3.text\": \"{{ $json.scene_titles[2] }}\",\n    \"Text-4.text\": \"{{ $json.scene_titles[3] }}\",\n    \"Text-5.text\": \"{{ $json.scene_titles[4] }}\"\n  }\n}","method":"POST","options":{},"sendBody":true,"contentType":"raw","sendHeaders":true,"rawContentType":"application/json","headerParameters":{"parameters":[{"name":"Authorization","value":"=Bearer {{ $('Set API Keys').item.json['Creatomate API Key'] }}"},{"name":"Content-Type","value":"application/json"}]}},"executeOnce":true,"typeVersion":4.2},{"id":"89c0e958-7690-4f3d-af49-3e9776f2c979","name":"Notify me on Discord","type":"n8n-nodes-base.discord","position":[2780,1140],"webhookId":"1541bc50-06e4-48e8-8c76-23850ee4edf6","parameters":{"content":"=A new Resume Studio POV video has been created: {{ $json.final_output }}","options":{},"authentication":"webhook"},"typeVersion":2},{"id":"14a09794-5e02-4880-b33d-139a91726dda","name":"Once Per Day","type":"n8n-nodes-base.scheduleTrigger","position":[-600,1220],"parameters":{"rule":{"interval":[{"triggerAtHour":7}]}},"typeVersion":1.2},{"id":"4de1f1c7-52ad-4e00-ad22-b4c3c0f718d8","name":"Load Google Sheet","type":"n8n-nodes-base.googleSheets","position":[-180,1220],"parameters":{"options":{"returnFirstMatch":true},"filtersUI":{"values":[{"lookupValue":"for production","lookupColumn":"production"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM/edit?usp=drivesdk","cachedResultName":"Sheet Template"}},"typeVersion":4.5,"alwaysOutputData":true},{"id":"e5c83690-1696-43aa-a0db-164ca128dd67","name":"Create List","type":"n8n-nodes-base.code","position":[280,1140],"parameters":{"jsCode":"// Get the text directly from the OpenAI response\nconst text = $input.first().json.choices[0].message.content;\n\n// Split the text on literal '\\\\n', trim, and filter empty lines\nconst lines = text.split('\\\\n').map(line => line.trim()).filter(line => line !== '');\n\n// Create an array of items for n8n\nconst items = lines.map(line => ({\n  json: {\n    response: { text: line }\n  }\n}));\n\n// Return the array of items\nreturn items;"},"typeVersion":2},{"id":"ed99df67-2068-4c8b-a6ba-e67d234f03c4","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1560,920],"parameters":{"color":3,"width":1360,"height":380,"content":"## 5. 📥Complete video with [Creatomate](https://creatomate.com/)\n### (total cost: $0.38 approx. with the Essential plan credits | Free trial credits available)\n1. First, the list of videos/captions is combined with the generated voice over into a single item containing all 3 elements.\n2. Those are then passed over to the Creatomate Template ID you specified, replacing the template captions/video/audio with your generated ones.\n3. When the video is finished rendering, it's then uploaded to Google Drive and the permissions set so it can be accessed with a link.\n4. Then we update the original Google Sheet template with the information from our generation, including tokens to calculate cost, then mark this idea as completed.\n5. Finally, we send a notification to via [webhook to the Discord server](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) when the video is ready to be downloaded and used!\n\n"},"typeVersion":1},{"id":"e7064a56-c500-4f9f-a54a-c4352c263b56","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-320,280],"parameters":{"width":620,"height":420,"content":"# 🤖 AI-Powered Short-Form Video Generator with OpenAI, Flux, Kling, and ElevenLabs\n\n## 📃Before you get started, you'll need:\n- [n8n installation](https://n8n.partnerlinks.io/n8nTTVideoGenTemplate) (tested on version 1.81.4)\n- [OpenAI API Key](https://platform.openai.com/api-keys) (free trial credits available)\n- [PiAPI](https://piapi.ai/?via=n8n) (free trial credits available)\n- [Eleven Labs](https://try.elevenlabs.io/n8n) (free account)\n- [Creatomate API Key](https://creatomate.com/) (free trial credits available)\n- Google Sheets API enabled in [Google Cloud Console](https://console.cloud.google.com/apis/api/sheets.googleapis.com/overview)\n- Google Drive API enabled in [Google Cloud Console](https://console.cloud.google.com/apis/api/drive.googleapis.com/overview)\n- OAuth 2.0 Client ID and Client Secret from your [Google Cloud Console Credentials](https://console.cloud.google.com/apis/credentials)\n"},"typeVersion":1},{"id":"4ddb7249-9785-4f51-b35c-b9a0c6a66e3b","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-480,780],"parameters":{"color":7,"width":920,"height":700,"content":"## 1. 🗨️Generate video captions from ideas in a Google Sheet\n\n1. Setup your API keys for [PiAPI](https://piapi.ai/?via=n8n), [Eleven Labs](https://try.elevenlabs.io/n8n), and [Creatomate](https://creatomate.com/).\n- Once logged in to your Creatomate account, create a new video template and click \"source code\" in the top right. [Paste this JSON code](https://pastebin.com/c7aMTeLK). This will be your example template for this workflow.\n- In your Creatomate template, click the \"Use Template\" button in the top right and then click \"API Integration\" and you'll see your template_id. Set this value as your Creatomate Template ID in the Set API Keys node\n\n2. The next node will load a Google Sheet, you can copy the [Google Sheet Template](https://docs.google.com/spreadsheets/d/1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM/edit?usp=sharing), simply choose File > Make a copy. Then in the Google Sheets node, connect to your copied sheet template.\n\n3. Next, we generate 5 captions for our video idea with OpenAI. You can edit this node to see the prompt and change it to your needs.\n\n4. In the final two nodes, we use custom javascript code to turn the OpenAI response into a list. Then, it validates to make sure the list was formed correctly (incase of an OpenAI failure to follow instructions)\n"},"typeVersion":1},{"id":"57ee2f8f-5371-4dab-b661-c58b25c7dd55","name":"Wait1","type":"n8n-nodes-base.wait","position":[1920,1140],"webhookId":"206d0cdf-b71f-44a7-909f-97df885c471a","parameters":{"unit":"minutes","amount":3},"typeVersion":1.1},{"id":"33781e51-ef30-437b-8499-94e39bfb38fa","name":"Get Final Video","type":"n8n-nodes-base.httpRequest","position":[2040,1140],"parameters":{"url":"=https://api.creatomate.com/v1/renders/{{ $('Render Final Video').item.json.id }}","options":{},"sendHeaders":true,"headerParameters":{"parameters":[{"name":"Authorization","value":"=Bearer {{ $('Set API Keys').item.json['Creatomate API Key'] }}"},{"name":"Content-Type","value":"application/json"}]}},"executeOnce":true,"typeVersion":4.2},{"id":"b0d0fe6f-39c2-4da6-9fcf-b0151ed2c351","name":"Upload Final Video","type":"n8n-nodes-base.googleDrive","position":[2300,1140],"parameters":{"name":"=POV-{{ $('Render Final Video').item.json.id }}.mp4","driveId":{"__rl":true,"mode":"list","value":"My Drive"},"options":{},"folderId":{"__rl":true,"mode":"list","value":"1w1EQ8xyth6w7AbX2wpDI3vInfYeRy8vH","cachedResultUrl":"https://drive.google.com/drive/folders/1w1EQ8xyth6w7AbX2wpDI3vInfYeRy8vH","cachedResultName":"Resume Studio"}},"credentials":{"googleDriveOAuth2Api":{"id":"2TbhWtnbRfSloGxX","name":"Google Drive account"}},"typeVersion":3},{"id":"3893d1de-7464-48ad-91a3-14b867c2a516","name":"Get Raw File","type":"n8n-nodes-base.httpRequest","position":[2160,1140],"parameters":{"url":"={{ $json.url }}","options":{"response":{"response":{"responseFormat":"file"}}}},"typeVersion":4.2},{"id":"74de5f28-f081-4ec5-a47e-681eb845f701","name":"Set Permissions","type":"n8n-nodes-base.googleDrive","position":[2440,1140],"parameters":{"fileId":{"__rl":true,"mode":"id","value":"={{ $json.id }}"},"options":{},"operation":"share","permissionsUi":{"permissionsValues":{"role":"writer","type":"anyone","allowFileDiscovery":true}}},"credentials":{"googleDriveOAuth2Api":{"id":"2TbhWtnbRfSloGxX","name":"Google Drive account"}},"typeVersion":3},{"id":"a2c07158-e949-4b5b-a92e-f4b021742831","name":"Update Google Sheet","type":"n8n-nodes-base.googleSheets","position":[2600,1140],"parameters":{"columns":{"value":{"id":"={{ $('Load Google Sheet').first().json.id }}","width":"={{ $('Get Raw File').item.json.width }}","height":"={{ $('Get Raw File').item.json.height }}","model1":"={{ $('Generate Video Captions').item.json.model }}","model2":"={{ $('Pair Videos with Audio').item.json.model }}","model3":"={{ $('Generate Script').item.json.model }}","duration":"={{ $('Get Raw File').item.json.duration }}","fluxCost":"0.075","frameRate":"={{ $('Get Raw File').item.json.frame_rate }}","klingCost":"2.3","production":"done","publishing":"for publishing","final_output":"={{ $('Upload Final Video').item.json.webContentLink }}","prompt1 input tokens":"={{ $('Generate Video Captions').item.json.usage.prompt_tokens }}","prompt2 input tokens":"={{ $('Pair Videos with Audio').item.json.input_tokens }}","prompt3 input tokens":"={{ $('Generate Script').item.json.usage.prompt_tokens }}","prompt1 output tokens":"={{ $('Generate Video Captions').item.json.usage.completion_tokens }}","prompt2 output tokens":"={{ $('Pair Videos with Audio').item.json.output_tokens }}","prompt3 output tokens":"={{ $('Generate Script').item.json.usage.completion_tokens }}"},"schema":[{"id":"id","type":"string","display":true,"removed":false,"required":false,"displayName":"id","defaultMatch":true,"canBeUsedToMatch":true},{"id":"idea","type":"string","display":true,"removed":false,"required":false,"displayName":"idea","defaultMatch":false,"canBeUsedToMatch":true},{"id":"caption","type":"string","display":true,"removed":false,"required":false,"displayName":"caption","defaultMatch":false,"canBeUsedToMatch":true},{"id":"production","type":"string","display":true,"removed":false,"required":false,"displayName":"production","defaultMatch":false,"canBeUsedToMatch":true},{"id":"environment_prompt","type":"string","display":true,"removed":false,"required":false,"displayName":"environment_prompt","defaultMatch":false,"canBeUsedToMatch":true},{"id":"publishing","type":"string","display":true,"removed":false,"required":false,"displayName":"publishing","defaultMatch":false,"canBeUsedToMatch":true},{"id":"final_output","type":"string","display":true,"removed":false,"required":false,"displayName":"final_output","defaultMatch":false,"canBeUsedToMatch":true},{"id":"width","type":"string","display":true,"removed":false,"required":false,"displayName":"width","defaultMatch":false,"canBeUsedToMatch":true},{"id":"height","type":"string","display":true,"removed":false,"required":false,"displayName":"height","defaultMatch":false,"canBeUsedToMatch":true},{"id":"duration","type":"string","display":true,"removed":false,"required":false,"displayName":"duration","defaultMatch":false,"canBeUsedToMatch":true},{"id":"frameRate","type":"string","display":true,"removed":false,"required":false,"displayName":"frameRate","defaultMatch":false,"canBeUsedToMatch":true},{"id":"model1","type":"string","display":true,"removed":false,"required":false,"displayName":"model1","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prompt1 input tokens","type":"string","display":true,"removed":false,"required":false,"displayName":"prompt1 input tokens","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prompt1 output tokens","type":"string","display":true,"removed":false,"required":false,"displayName":"prompt1 output tokens","defaultMatch":false,"canBeUsedToMatch":true},{"id":"model1 cost","type":"string","display":true,"removed":false,"required":false,"displayName":"model1 cost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"model2","type":"string","display":true,"removed":false,"required":false,"displayName":"model2","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prompt2 input tokens","type":"string","display":true,"removed":false,"required":false,"displayName":"prompt2 input tokens","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prompt2 output tokens","type":"string","display":true,"removed":false,"required":false,"displayName":"prompt2 output tokens","defaultMatch":false,"canBeUsedToMatch":true},{"id":"model2 cost","type":"string","display":true,"removed":false,"required":false,"displayName":"model2 cost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"model3","type":"string","display":true,"removed":false,"required":false,"displayName":"model3","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prompt3 input tokens","type":"string","display":true,"removed":false,"required":false,"displayName":"prompt3 input tokens","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prompt3 output tokens","type":"string","display":true,"removed":false,"required":false,"displayName":"prompt3 output tokens","defaultMatch":false,"canBeUsedToMatch":true},{"id":"model3 cost","type":"string","display":true,"removed":false,"required":false,"displayName":"model3 cost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"cmCost","type":"string","display":true,"removed":false,"required":false,"displayName":"cmCost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"upgradeCmCost","type":"string","display":true,"removed":false,"required":false,"displayName":"upgradeCmCost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"fluxCost","type":"string","display":true,"removed":false,"required":false,"displayName":"fluxCost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"klingCost","type":"string","display":true,"removed":false,"required":false,"displayName":"klingCost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"totalCost","type":"string","display":true,"removed":false,"required":false,"displayName":"totalCost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"datePosted","type":"string","display":true,"removed":false,"required":false,"displayName":"datePosted","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM/edit?usp=drivesdk","cachedResultName":"Sheet Template"}},"credentials":{"googleSheetsOAuth2Api":{"id":"3IOU2VjBnR4hGohx","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"62423325-f9da-4cdf-8864-c011fb4fa14f","name":"Set API Keys","type":"n8n-nodes-base.set","notes":"SET BEFORE STARTING","position":[-380,1220],"parameters":{"options":{},"assignments":{"assignments":[{"id":"35659353-d8e2-4677-876b-401b549605a0","name":"PiAPI Key","type":"string","value":""},{"id":"c4927dd6-c597-48fe-b7c1-bbffcf5ff02f","name":"ElevenLabs API Key","type":"string","value":""},{"id":"f5e90c05-dd24-4918-9005-4c87a4fb344d","name":"Creatomate API Key","type":"string","value":""},{"id":"d0ebba50-5a99-4090-adcb-d18aa0b21be2","name":"Creatomate Template ID","type":"string","value":""}]}},"notesInFlow":true,"typeVersion":3.4},{"id":"4252d793-5f16-4d5e-bb78-9b155aef5d3e","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-440,1160],"parameters":{"color":3,"width":220,"height":220,"content":"## DO THIS FIRST\n"},"typeVersion":1},{"id":"845d5b4a-8a3f-4d0d-afce-39aa4e349a7b","name":"Validate list formatting","type":"n8n-nodes-base.if","position":[280,1280],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"2681c0e9-aa45-4f0f-8933-6e6de324c7aa","operator":{"type":"array","operation":"lengthGt","rightType":"number"},"leftValue":"={{$input.all()}}","rightValue":1}]}},"typeVersion":2.2},{"id":"98a3761e-544a-473c-aa7f-cc14390750d8","name":"Get Audio from Video","type":"@n8n/n8n-nodes-langchain.openAi","notes":"Extract the audio from video for generate the description","position":[3820,1360],"parameters":{"options":{},"resource":"audio","operation":"transcribe"},"credentials":{"openAiApi":{"id":"XJdxgMSXFgwReSsh","name":"n8n key"}},"notesInFlow":true,"retryOnFail":true,"typeVersion":1,"waitBetweenTries":5000},{"id":"ec498643-1ef1-42e5-90ee-ec49d0e2b63b","name":"Generate Description for Videos  in Tiktok and Instagram","type":"@n8n/n8n-nodes-langchain.openAi","notes":"Request to OpenAi for generate description with the audio extracted from the video","position":[4060,1360],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"GPT-4O"},"options":{},"messages":{"values":[{"role":"system","content":"You are an expert assistant in creating engaging social media video titles."},{"content":"=I'm going to upload a video to social media. Here are some examples of descriptions that have worked well on Instagram:\n\nFollow and save for later. Discover InfluencersDe, the AI tool that automates TikTok creation and publishing to drive traffic to your website. Perfect for entrepreneurs and brands.\n#digitalmarketing #ugc #tiktok #ai #influencersde #contentcreation\n\nDiscover the video marketing revolution with InfluencersDe!\n.\n.\n.\n#socialmedia #videomarketing #ai #tiktok #influencersde #growthhacking\n\nDon't miss InfluencersDe, the tool that transforms your marketing strategy with just one click!\n.\n.\n.\n#ugc #ai #tiktok #digitalmarketing #influencersde #branding\n\nCan you create another title for the Instagram post based on this recognized audio from the video?\n\nAudio: {{ $('Get Audio from Video').item.json.text }}\n\nIMPORTANT: Reply only with the description, don't add anything else."}]}},"credentials":{"openAiApi":{"id":"XJdxgMSXFgwReSsh","name":"n8n key"}},"notesInFlow":true,"retryOnFail":true,"typeVersion":1.4,"waitBetweenTries":5000},{"id":"2f9f753d-86f3-4489-9dd2-a691f2da80ba","name":"Upload Video and Description to Tiktok","type":"n8n-nodes-base.httpRequest","notes":"Generate in upload-post.com the token and add to the credentials in the header-> Authorization: Apikey (token here)","position":[4880,940],"parameters":{"url":"https://api.upload-post.com/api/upload","method":"POST","options":{},"sendBody":true,"contentType":"multipart-form-data","authentication":"genericCredentialType","bodyParameters":{"parameters":[{"name":"title","value":"={{ $('Generate Description for Videos  in Tiktok and Instagram').item.json.message.content.replaceAll(\"\\\"\", \"\") }}"},{"name":"platform[]","value":"tiktok"},{"name":"video","parameterType":"formBinaryData","inputDataFieldName":"data"},{"name":"user","value":"Add user generated in upload-post"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"WNjAx7UqrEZ1JDrR","name":"VituManco"}},"notesInFlow":true,"typeVersion":4.2},{"id":"4f007ef7-3f0a-4b4d-8dca-96028f29dd0c","name":"Upload Video and Description to Instagram","type":"n8n-nodes-base.httpRequest","notes":"Generate in upload-post.com the token and add to the credentials in the header-> Authorization: Apikey (token here)","position":[4880,1140],"parameters":{"url":"https://api.upload-post.com/api/upload","method":"POST","options":{},"sendBody":true,"contentType":"multipart-form-data","authentication":"genericCredentialType","bodyParameters":{"parameters":[{"name":"title","value":"={{ $('Generate Description for Videos  in Tiktok and Instagram').item.json.message.content.replaceAll(\"\\\"\", \"\") }}"},{"name":"platform[]","value":"instagram"},{"name":"video","parameterType":"formBinaryData","inputDataFieldName":"data"},{"name":"user","value":"Add user generated in upload-post"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"47dO31ED0WIaJkR6","name":"Header Auth account"}},"notesInFlow":true,"typeVersion":4.2},{"id":"3805750b-65c4-4f28-b811-967681eda0ff","name":"Upload Video and Description to Youtube","type":"n8n-nodes-base.httpRequest","notes":"Generate in upload-post.com the token and add to the credentials in the header-> Authorization: Apikey (token here)","position":[4880,1360],"parameters":{"url":"https://api.upload-post.com/api/upload","method":"POST","options":{},"sendBody":true,"contentType":"multipart-form-data","authentication":"genericCredentialType","bodyParameters":{"parameters":[{"name":"title","value":"={{ $('Generate Description for Videos  in Tiktok and Instagram').item.json.message.content.replaceAll(\"\\\"\", \"\").substring(0, 70) }}\n"},{"name":"platform[]","value":"youtube"},{"name":"video","parameterType":"formBinaryData","inputDataFieldName":"data"},{"name":"user","value":"Add user generated in upload-post"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"47dO31ED0WIaJkR6","name":"Header Auth account"}},"notesInFlow":true,"typeVersion":4.2},{"id":"754e3f54-87cd-4b50-947e-a9b20ce2d2ab","name":"Upload Video and Description to Facebook","type":"n8n-nodes-base.httpRequest","notes":"Generate in upload-post.com the token and add to the credentials in the header-> Authorization: Apikey (token here)","position":[4880,1600],"parameters":{"url":"https://api.upload-post.com/api/upload","method":"POST","options":{},"sendBody":true,"contentType":"multipart-form-data","authentication":"genericCredentialType","bodyParameters":{"parameters":[{"name":"title","value":"={{ $('Generate Description for Videos  in Tiktok and Instagram').item.json.message.content.replaceAll(\"\\\"\", \"\") }}"},{"name":"platform[]","value":"facebook"},{"name":"video","parameterType":"formBinaryData","inputDataFieldName":"data"},{"name":"user","value":"Add user generated in upload-post"},{"name":"facebook_page_id","value":"61556896550301"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"47dO31ED0WIaJkR6","name":"Header Auth account"}},"notesInFlow":true,"typeVersion":4.2},{"id":"4090c098-2381-4e57-8e53-d24a2bed57cd","name":"Upload Video and Description to Linkedin","type":"n8n-nodes-base.httpRequest","notes":"Generate in upload-post.com the token and add to the credentials in the header-> Authorization: Apikey (token here)","position":[4880,1840],"parameters":{"url":"https://api.upload-post.com/api/upload","method":"POST","options":{},"sendBody":true,"contentType":"multipart-form-data","authentication":"genericCredentialType","bodyParameters":{"parameters":[{"name":"title","value":"={{ $('Generate Description for Videos  in Tiktok and Instagram').item.json.message.content.replaceAll(\"\\\"\", \"\") }}"},{"name":"platform[]","value":"linkedin"},{"name":"video","parameterType":"formBinaryData","inputDataFieldName":"data"},{"name":"user","value":"Add user generated in upload-post"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"47dO31ED0WIaJkR6","name":"Header Auth account"}},"notesInFlow":true,"typeVersion":4.2},{"id":"cd9fbbf5-262e-43bc-9c09-382516de1cca","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[2940,920],"parameters":{"width":2480,"height":1160,"content":"## 6. Upload to all social networks with upload-post.com\n### (premium plan 15$ | Free trial credits available)\n\n\n\nThis automation will automatically create descriptions from videos and upload it to Instagram, TikTok, Youtube, Facebook and Linkedin.\n\n## How to Use\n1. Generate an API token at upload-post.com and add to Upload to Tiktok and Upload to Instagram nodes etc\n2. Customize the OpenAI prompt for your specific use case\n3. Optional: Configure Telegram for error notifications\n\n## Requirements\n- upload-post.com account\n- OpenAI API key\n"},"typeVersion":1},{"id":"f3524df6-484b-40e6-a9a3-f4d2211f3988","name":"Read Video from Google Drive","type":"n8n-nodes-base.readBinaryFile","position":[4420,1360],"parameters":{"filePath":"={{ $('Write video').item.json.originalFilename.replaceAll(\" \", \"_\") }}","dataPropertyName":"datavideo"},"typeVersion":1},{"id":"f082675c-1682-4679-88df-ae410e323f5b","name":"Write video","type":"n8n-nodes-base.writeBinaryFile","position":[3440,1360],"parameters":{"options":{},"fileName":"={{ $json.originalFilename.replaceAll(\" \", \"_\") }}"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"8f78312c-a5e3-48f0-a386-e1251586a6e7","connections":{"Wait1":{"main":[[{"node":"Get Final Video","type":"main","index":0}]]},"Get Video":{"main":[[{"node":"Fail check","type":"main","index":0}]]},"Get image":{"main":[[{"node":"Check for failures","type":"main","index":0}]]},"Wait 3min":{"main":[[{"node":"Get image","type":"main","index":0}]]},"Wait 5min":{"main":[[{"node":"Generate Image","type":"main","index":0}]]},"Fail check":{"main":[[{"node":"Wait to retry","type":"main","index":0}],[{"node":"Match captions with videos","type":"main","index":1}]]},"Wait 10min":{"main":[[{"node":"Get Video","type":"main","index":0}]]},"Create List":{"main":[[{"node":"Validate list formatting","type":"main","index":0}]]},"Write video":{"main":[[{"node":"Get Audio from Video","type":"main","index":0}]]},"Get Raw File":{"main":[[{"node":"Upload Final Video","type":"main","index":0},{"node":"Write video","type":"main","index":0}]]},"Once Per Day":{"main":[[{"node":"Set API Keys","type":"main","index":0}]]},"Set API Keys":{"main":[[{"node":"Load Google Sheet","type":"main","index":0}]]},"List Elements":{"main":[[{"node":"Pair Videos with Audio","type":"main","index":0}]]},"Wait to retry":{"main":[[{"node":"Image-to-Video","type":"main","index":0}]]},"Generate Image":{"main":[[{"node":"Wait 3min","type":"main","index":0}]]},"Generate voice":{"main":[[{"node":"Upload Voice Audio","type":"main","index":0}]]},"Image-to-Video":{"main":[[{"node":"Wait 10min","type":"main","index":0}]]},"List Elements1":{"main":[[{"node":"Pair Videos with Audio","type":"main","index":1}]]},"Generate Script":{"main":[[{"node":"Generate voice","type":"main","index":0}]]},"Get Final Video":{"main":[[{"node":"Get Raw File","type":"main","index":0}]]},"Set Permissions":{"main":[[{"node":"Update Google Sheet","type":"main","index":0}]]},"Load Google Sheet":{"main":[[{"node":"Generate Video Captions","type":"main","index":0}]]},"Check for failures":{"main":[[{"node":"Wait 5min","type":"main","index":0}],[{"node":"Image-to-Video","type":"main","index":0}]]},"Render Final Video":{"main":[[{"node":"Wait1","type":"main","index":0}]]},"Upload Final Video":{"main":[[{"node":"Set Permissions","type":"main","index":0}]]},"Upload Voice Audio":{"main":[[{"node":"Set Access Permissions","type":"main","index":0}]]},"Update Google Sheet":{"main":[[{"node":"Notify me on Discord","type":"main","index":0}]]},"Get Audio from Video":{"main":[[{"node":"Generate Description for Videos  in Tiktok and Instagram","type":"main","index":0}]]},"Notify me on Discord":{"main":[[]]},"Calculate Token Usage":{"main":[[{"node":"Generate Image","type":"main","index":0}]]},"Generate Image Prompts":{"main":[[{"node":"Calculate Token Usage","type":"main","index":0}]]},"Pair Videos with Audio":{"main":[[{"node":"Render Final Video","type":"main","index":0}]]},"Set Access Permissions":{"main":[[{"node":"List Elements1","type":"main","index":0}]]},"Generate Video Captions":{"main":[[{"node":"Create List","type":"main","index":0}]]},"Validate list formatting":{"main":[[{"node":"Generate Image Prompts","type":"main","index":0},{"node":"Match captions with videos","type":"main","index":0},{"node":"Generate Script","type":"main","index":0}],[{"node":"Generate Video Captions","type":"main","index":0}]]},"Match captions with videos":{"main":[[{"node":"List Elements","type":"main","index":0}]]},"Read Video from Google Drive":{"main":[[{"node":"Upload Video and Description to Tiktok","type":"main","index":0},{"node":"Upload Video and Description to Instagram","type":"main","index":0},{"node":"Upload Video and Description to Youtube","type":"main","index":0},{"node":"Upload Video and Description to Facebook","type":"main","index":0},{"node":"Upload Video and Description to Linkedin","type":"main","index":0}]]},"Generate Description for Videos  in Tiktok and Instagram":{"main":[[{"node":"Read Video from Google Drive","type":"main","index":0}]]}}}


