# templates

name: Save Time with AI Hiring – Automate Screening, Assessments, Alerts & Interviews
author_name: Aayushman Sharma
author_username: ajstyle0411
categories: []
created_at: 2025-06-09T11:01:53.274Z
updated_at: 2025-06-09T11:01:53.274Z
url: https://n8n.io/workflows/4813
scraped_at: 2025-06-19 22:48:52
description:
  AI Recruitment Automation Pipeline – Resume Parsing, GPT-4 Evaluation, Assessment Triggers & Interview Scheduling

  This end-to-end AI-powered HR recruitment workflow automates the entire candidate journey — from resume collection and parsing to AI-based evaluation, Talent Acquisition (TA) approvals, assessment dispatch, and interview scheduling. Built in n8n, it leverages OpenAI GPT-4, Google Sheets, Google Drive, Slack, and SMTP to reduce hiring time, improve candidate quality, and eliminate repetitive manual tasks.

  Key Features

  Smart Resume Intake Form
  Collects candidate data: name, email, phone, LinkedIn, job role, and CV (PDF).
  Custom-designed UI with branding-ready CSS.

  PDF Resume Parsing & Storage
  CV is uploaded to a dedicated Google Drive folder.
  Resume text is extracted for semantic analysis.

  AI-Based Candidate Evaluation (GPT-4 via LangChain)
  Extracts: City, Education, Job History, Skills.
  Summarizes candidate profile (100 words).
  Retrieves and summarizes job description from Google Sheets.
  Performs detailed evaluation:
    ✅ Semantic fit scoring (0–100%)
    ✅ Key matches and skill gaps
    ✅ Soft skills extraction
    ✅ Red flag detection (job-hopping, missing info)
    ✅ Final score (1–10) with rationale

  Google Sheets Integration
  Logs and updates candidate data at each stage:
    CV Submitted → Scored → Shortlisted → Assessment Sent → Interview Scheduled → Rejected

  TA Approval via Email (Send & Wait)
  TA receives evaluation summary and gives one-click approve/reject.
  ✅ Approved → Status: Resume Selected  
  ❌ Rejected → Status: Resume Rejected

  Assessment Trigger (Post Approval)
  Sends assessment link to shortlisted candidates.
  Notifies TA via Slack and Email when assessment is submitted.

  Interview Scheduling
  Sends Calendly link for self-scheduled interview booking.
  Candidate receives detailed next-step instructions.

  Status-Based Candidate Emails
  Automatically sends:
    ✔️ Shortlisting confirmation + interview setup
    ❌ Rejection email with branded message

  Business Benefits

  Save 80%+ time** spent on manual resume reviews and coordination
  Reduce cost-per-hire** by eliminating manual tasks
  Enhance hiring accuracy** with structured, AI-based decision-making
  Scalable recruitment** for 100s of candidates per week
  Improve candidate experience** with instant status updates
  Centralize data** in Google Sheets for full team visibility

  🔧 Setup Instructions

  1. Google Service Account Setup (One-Time)

  Before using Google Sheets or Google Drive in n8n:

  Go to Google Cloud Console.
  Create a Service Account under your project.
  Enable these APIs:
    Google Sheets API
    Google Drive API
  Download the JSON credentials for the service account.
  IMPORTANT:  
    Share your target Google Sheets and Docs with the service account email  
    (e.g., your-service-account@your-project.iam.gserviceaccount.com).

  Add Applicant's Details to Google Sheet

  Document**: Select the Profiles Google Sheet document.
  Sheet**: Select the Applicant's Details sheet.
  Fields to Map**:
    EMAIL: {{ $('On form submission').item.json.Email }}
    DATE: {{ $now.format('dd-MM-yyyy') }}
    NAME: {{ $('On form submission').item.json.Name }}
    LINKEDIN URL: {{ $('On form submission').item.json["LinkedIn Profile URL"] }}
    JOB PROFILE: {{ $('On form submission').item.json["Job Openings"] }}
    STATUS: CV SUBMITTED
    LAST UPDATED DATE: {{ $now.format('dd-MM-yyyy hh:mm:ss') }}

  Extract Applicant's Resume Text

  Text**:  
    {{ $('Extract from File').item.json.text }}

  Get Job Description from Google Sheet

  Document**: Profiles
  Sheet**: Job Openings
  Filter**:
  Column**: Job Profile
  Value**: {{ $('On form submission').item.json["Job Openings"] }}

  Save Evaluation Results in Google Sheets

  Document**: Profiles
  Sheet**: Applicant's Details
  Column Match On**: EMAIL
  Fields to Map**:
  EMAIL: {{ $('On form submission').item.json.Email }}
  CITY: {{ $('Applicant\'s Details').item.json.output.City }}
  EDUCATIONAL: {{ $('Applicant\'s Details').item.json.output["Educational Qualification"] }}
  JOB HISTORY: {{ $('Applicant\'s Details').item.json.output["Job History"] }}
  SKILLS: {{ $('Applicant\'s Details').item.json.output.Skills }}
  SUMMARIZE: {{ $('Summarize Applicant\'s Profile').item.json.response.text }}
  SEMANTIC FIT SCORE: {{ $json.output.semantic_fit.score }}
  KEY MATCHES: {{ $json.output.semantic_fit.key_matches.toJsonString() }}
  KEY GAPS: {{ $json.output.semantic_fit.key_gaps.toJsonString() }}
  SEMANTIC FIT CONSIDERATION: {{ $json.output.semantic_fit.consideration }}
  SOFT SKILLS: {{ $json.output.soft_skills.toJsonString() }}
  EXPERIENCE GAP DETECTED: {{ $json.output.experience_analysis.experience_gap_detected }}
  OVER QUALIFICATION DETECTED: {{ $json.output.experience_analysis.overqualification_detected }}
  EXPERIENCE ANALYSIS CONSIDERATION: {{ $json.output.experience_analysis.consideration }}
  RED FLAGS ISSUES DETECTED: {{ $json.output.red_flags.issues_detected.toJsonString() }}
  RED FLAGS CONSIDERATION: {{ $json.output.red_flags.consideration }}
  VOTE: {{ $json.output.overall_evaluation.final_vote }}
  FINAL CONSIDERATION: {{ $json.output.overall_evaluation.consideration }}
  STATUS: CV SCORED
  LAST UPDATED DATE: {{ $now.format('dd-MM-yyyy hh:mm:ss') }}

  Update Applicant Statuses

  Resume Selected

  Document**: Profiles
  Sheet**: Applicant's Details
  Column Match On**: EMAIL
  Update**:
  STATUS: RESUME SELECTED
  LAST UPDATED DATE: {{ $now.format('dd-MM-yyyy hh:mm:ss') }}

  Resume Rejected

  Update**:
  STATUS: RESUME REJECTED
  LAST UPDATED DATE: {{ $now.format('dd-MM-yyyy hh:mm:ss') }}

  Assessment Sent

  Email**: {{ $('Loop to Send Assessment Link to Each Candidate').item.json.EMAIL }}
  Update**:
  STATUS: ASSESSMENT SENT
  LAST UPDATED DATE: {{ $now.format('dd-MM-yyyy hh:mm:ss') }}

  Assessment Submitted

  Email**: {{ $json["Enter Your Email Address"] }}
  Update**:
  STATUS: ASSESSMENT SUBMITTED
  LAST UPDATED DATE: {{ $now.format('dd-MM-yyyy hh:mm:ss') }}

  Interview Booked

  Email**: {{ $json.payload.email }}
  Update**:
  STATUS: INTERVIEW BOOKED
  LAST UPDATED DATE: {{ $now.format('dd-MM-yyyy hh:mm:ss') }}

  Fetch Applicants with Specific Status

  Status: RESUME SELECTED

  Document**: Profiles
  Sheet**: Applicant's Details
  Filter**:
  Column**: STATUS
  Value**: RESUME SELECTED

  Get Assessment Form URL from Job Profile

  Document**: Profiles
  Sheet**: Job Openings
  Filter**:
  Column**: Job Profile
  Value**: {{ $json["JOB PROFILE"] }}

  Trigger on Applicant Status Update

  Document**: Profiles
  Sheet**: Applicant's Details
  Trigger Settings**:
  Columns to Watch**: STATUS

  ⚠️ Important Notes

  Always use “Select Document from List” instead of manually pasting the sheet/document ID.
  Share your Sheets/Docs with the Google Service Account email for proper access.
  Keep your date formats consistent using {{ $now.format('dd-MM-yyyy hh:mm:ss') }}.

  Add credentials for:
     Google Drive
     Google Sheets
     SMTP (for emails)
     OpenAI API Key (GPT-4)
  Replace placeholders:
     Google Sheet & Folder IDs
     Calendly Link
     Assessment Link
  (Optional) Customize GPT-4 prompts for domain-specific scoring
  (Optional) Use your Slack webhook for TA notifications

  🛠️ Tools & Integrations

  Form Trigger** – Candidate form with file upload  
  Google Drive + Extract PDF** – CV parsing  
  Google Sheets** – Database for all applicant statuses  
  LangChain GPT-4 Nodes** – AI profile + job analysis  
  Email Send & Send & Wait** – Candidate/TA communication  
  IF Node** – Logic for approve/reject  
  Slack Integration** – TA notification  
  Calendly Link** – Interview scheduling

  AI resume screening, GPT-4 recruitment workflow, automated hiring pipeline, semantic fit evaluation, LangChain for HR, resume parsing automation, AI in talent acquisition, assessment workflow automation, interview scheduling automation, candidate shortlisting automation, OpenAI HR integration, Google Sheets recruitment tracker, n8n HR automation template, self-scheduling interviews with Calendly, Slack notifications in recruitment

nodes_used:
  ["n8n-nodes-base.emailSend","n8n-nodes-base.googleSheets","n8n-nodes-base.slack","n8n-nodes-base.googleDrive","@n8n/n8n-nodes-langchain.chainSummarization","@n8n/n8n-nodes-langchain.chainLlm","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.outputParserStructured","@n8n/n8n-nodes-langchain.informationExtractor"]

workflow_json:
  {"meta":{"instanceId":"b0c38aaab6bebe08413b40e26aa2ee99136cd8edfd3a296014b1e2af1b2d5383"},"nodes":[{"id":"8a152592-2259-4884-92dc-6e23158bf58f","name":"On form submission","type":"n8n-nodes-base.formTrigger","position":[280,420],"webhookId":"2a87705d-8ba1-41f1-80ef-85f364ce253e","parameters":{},"typeVersion":2.2},{"id":"eda2a030-df56-4989-9986-2d6837b71c78","name":"Extract from File","type":"n8n-nodes-base.extractFromFile","position":[680,420],"parameters":{},"typeVersion":1},{"id":"6a848708-0a9b-4bbf-bcf7-4f7195e6196d","name":"Structured Output Parser","type":"@n8n/n8n-nodes-langchain.outputParserStructured","position":[2960,560],"parameters":{},"typeVersion":1.2},{"id":"da721ba9-e799-4eb0-8d5f-d65eec959cbe","name":"Upload CV","type":"n8n-nodes-base.googleDrive","position":[680,220],"parameters":{},"typeVersion":3},{"id":"f989cbb1-4eb8-4c77-ac03-5f5703afbc76","name":"OpenAI","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[1700,780],"parameters":{},"typeVersion":1.2},{"id":"e7b5b83c-042c-445c-869d-06d18aaba7d8","name":"Applicant's Details","type":"@n8n/n8n-nodes-langchain.informationExtractor","position":[1320,420],"parameters":{},"typeVersion":1},{"id":"8a537b27-4418-406b-a204-04249295298a","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[0,280],"parameters":{"content":""},"typeVersion":1},{"id":"ca220bd7-6621-4920-b9ea-47ed338fd0e9","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[560,0],"parameters":{"content":""},"typeVersion":1},{"id":"8405dc04-3d99-45f0-a93b-2343e7ad5583","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[920,240],"parameters":{"content":""},"typeVersion":1},{"id":"e66f542e-2a8d-46ee-95df-aa2655b12be4","name":"Add Applicant's Details in Google Sheet","type":"n8n-nodes-base.googleSheets","position":[1040,420],"parameters":{},"typeVersion":4.5},{"id":"d04a0c55-546d-41aa-91c5-c9fe0941981b","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1280,240],"parameters":{"content":""},"typeVersion":1},{"id":"e90fc56b-7878-46f3-a079-e95dab695f9f","name":"Summarize Applicant's Profile","type":"@n8n/n8n-nodes-langchain.chainSummarization","position":[1680,420],"parameters":{},"typeVersion":2},{"id":"d9c3773a-daa4-4f71-970d-d4d7ea2ddbf3","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[1640,240],"parameters":{"content":""},"typeVersion":1},{"id":"22b9732c-82b9-4eba-b195-62fd08744cce","name":"Get Job Description from Google Sheets","type":"n8n-nodes-base.googleSheets","position":[2120,420],"parameters":{},"typeVersion":4.5},{"id":"664e0387-c69b-4f4a-a431-db2e9fc98d3f","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[2000,240],"parameters":{"content":""},"typeVersion":1},{"id":"e7dbb219-28da-40d4-806b-ff44be167cc4","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[2360,240],"parameters":{"content":""},"typeVersion":1},{"id":"ce417cff-854e-4e5b-8ff8-966f132fa07e","name":"Summarize Job Role Description","type":"@n8n/n8n-nodes-langchain.chainSummarization","position":[2400,420],"parameters":{},"typeVersion":2},{"id":"3c684c15-bfc4-48ca-990f-c8bb12bb809a","name":"Semantic Fit & Evaluation by HR Expert","type":"@n8n/n8n-nodes-langchain.chainLlm","position":[2760,420],"parameters":{},"typeVersion":1.5},{"id":"6940c4b0-b6b3-4e69-9203-a5c298ed77da","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[2720,140],"parameters":{"content":""},"typeVersion":1},{"id":"c43f554f-4d28-407e-aa32-164af6be244e","name":"Update Evaluation Results in Google Sheets","type":"n8n-nodes-base.googleSheets","position":[2120,900],"parameters":{},"typeVersion":4.5},{"id":"bcde088b-7689-42e5-9cdc-7bedd070ccd8","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[2000,720],"parameters":{"content":""},"typeVersion":1},{"id":"4190f1dc-88f2-4b97-bc2d-3cbb94e687c4","name":"Sticky Note9","type":"n8n-nodes-base.stickyNote","position":[2360,720],"parameters":{"content":""},"typeVersion":1},{"id":"0e84b074-633a-4b45-8150-c8e734adcdf6","name":"Notify TA for Approval via Email","type":"n8n-nodes-base.emailSend","position":[2480,900],"webhookId":"6941e6ef-63b6-43f9-8911-32fdd84d13fe","parameters":{},"typeVersion":2.1},{"id":"73b71de6-ea39-456b-8c39-c4debef14f5f","name":"Approval Check - IF Condition","type":"n8n-nodes-base.if","position":[2840,900],"parameters":{},"typeVersion":2.2},{"id":"aa7c8080-62a9-47e8-90e1-35594164ac7d","name":"Sticky Note10","type":"n8n-nodes-base.stickyNote","position":[2720,720],"parameters":{"content":""},"typeVersion":1},{"id":"2c6d927f-d7e2-4a61-aef1-6f0eb0273792","name":"Sticky Note11","type":"n8n-nodes-base.stickyNote","position":[3520,320],"parameters":{"content":""},"typeVersion":1},{"id":"2abddb6e-c726-4610-9cb4-3acf1f6e2b18","name":"Send Shortlist Email to Candidate","type":"n8n-nodes-base.emailSend","position":[3620,500],"webhookId":"5b12b59d-c5b3-44b4-8359-e69ce6401120","parameters":{},"typeVersion":2.1},{"id":"0adc3251-c510-4ec8-8cb3-38200ac9cfa8","name":"Send Rejection Email to Candidate","type":"n8n-nodes-base.emailSend","position":[3620,920],"webhookId":"5b12b59d-c5b3-44b4-8359-e69ce6401120","parameters":{},"typeVersion":2.1},{"id":"0eb1fa6a-f927-4dcf-90b6-82a5c75d09e5","name":"Sticky Note12","type":"n8n-nodes-base.stickyNote","position":[3520,740],"parameters":{"content":""},"typeVersion":1},{"id":"f0f37e05-5b00-42bb-aa9d-80a1855791a6","name":"Sticky Note14","type":"n8n-nodes-base.stickyNote","position":[3120,300],"parameters":{"content":""},"typeVersion":1},{"id":"72ba03a4-5dd8-4d42-b2f4-3adee73df626","name":"Update Applicant's Status as REJECTED","type":"n8n-nodes-base.googleSheets","position":[3240,920],"parameters":{},"typeVersion":4.5},{"id":"81b96523-426f-4d78-bf48-ded4df362faa","name":"Sticky Note15","type":"n8n-nodes-base.stickyNote","position":[3120,740],"parameters":{"content":""},"typeVersion":1},{"id":"cc11a04b-543d-44a7-9f24-31fe71307e2c","name":"Run Daily at 09:00 AM","type":"n8n-nodes-base.scheduleTrigger","position":[100,920],"parameters":{},"typeVersion":1.2},{"id":"bd500d66-fb06-405e-b278-dc570d7f5da5","name":"Fetch Records with Status \"Resume Selected\"","type":"n8n-nodes-base.googleSheets","position":[320,920],"parameters":{},"typeVersion":4.5},{"id":"c1c21c4b-03bc-49a9-a1a3-5bcf9d20931b","name":"Loop to Send Assessment Link to Each Candidate","type":"n8n-nodes-base.splitInBatches","position":[580,920],"parameters":{},"typeVersion":3},{"id":"7037b68b-4b0b-447f-b51f-be8039995ed7","name":"Get Assessment Form URL","type":"n8n-nodes-base.googleSheets","position":[880,940],"parameters":{},"typeVersion":4.5},{"id":"3e155bf1-b5eb-4c86-aa9b-5b7773be15eb","name":"Send Assessment Submission Email","type":"n8n-nodes-base.emailSend","position":[1160,940],"webhookId":"92dfdc70-ac6d-468d-ae75-fb2c42b8a554","parameters":{},"typeVersion":2.1},{"id":"585c6022-b645-480f-a2d9-99a114609fbc","name":"Update Status to Assessment Sent","type":"n8n-nodes-base.googleSheets","position":[1440,940],"parameters":{},"typeVersion":4.5},{"id":"9930d8fd-a3fa-43a1-9a8c-1bef8876cb61","name":"Sticky Note17","type":"n8n-nodes-base.stickyNote","position":[0,720],"parameters":{"content":""},"typeVersion":1},{"id":"7e40f8fa-df27-418e-9dc6-3cc73202feea","name":"Technical Support Engineer Assessment Trigger","type":"n8n-nodes-base.typeformTrigger","position":[140,1580],"webhookId":"5d14bba3-737d-432a-b426-ecba0826e30a","parameters":{},"typeVersion":1.1},{"id":"675b08ff-2a53-45fc-ba61-c21657b0d123","name":"Technical Project Manager Assessment Trigger","type":"n8n-nodes-base.typeformTrigger","position":[140,1360],"webhookId":"5d14bba3-737d-432a-b426-ecba0826e30a","parameters":{},"typeVersion":1.1},{"id":"c35f75d4-eac8-42b6-8a18-7e7643c4c51e","name":"Update Applicant Status to Assessment Submitted","type":"n8n-nodes-base.googleSheets","position":[420,1460],"parameters":{},"typeVersion":4.5},{"id":"f32d787a-36b6-4cbf-aee1-1e7bc261092a","name":"Notify TA via Email for Assessment Submission","type":"n8n-nodes-base.emailSend","position":[740,1360],"webhookId":"92dfdc70-ac6d-468d-ae75-fb2c42b8a554","parameters":{},"typeVersion":2.1},{"id":"1dbd8726-60ad-4367-aa61-3dbdd1868cbf","name":"Notify TA via Slack for Assessment Submission","type":"n8n-nodes-base.slack","disabled":true,"position":[740,1580],"webhookId":"39e62d5a-b2e4-4912-a8d7-be43e1fe780f","parameters":{},"typeVersion":2.3},{"id":"2ce49266-9987-4e2d-91ed-a8b570f44af2","name":"Trigger when Interview booked by applicant in calendly","type":"n8n-nodes-base.calendlyTrigger","position":[560,1880],"webhookId":"b138a41c-e292-4533-8b02-7a3fea7b73e3","parameters":{},"typeVersion":1},{"id":"1d27e489-0d47-4cb7-a4c6-6cc75f410302","name":"Update Status to Interview Booked","type":"n8n-nodes-base.googleSheets","position":[780,1880],"parameters":{},"typeVersion":4.6},{"id":"cfe93e15-863b-447d-826c-3f319fec28ba","name":"Get Triggered when Applicant Status Update in Google Sheet","type":"n8n-nodes-base.googleSheetsTrigger","position":[1240,1720],"parameters":{},"typeVersion":1},{"id":"5ff66e2e-c71d-48cc-bf66-df4d4c616569","name":"Route actions based on Status","type":"n8n-nodes-base.switch","position":[1480,1640],"parameters":{},"typeVersion":3.2},{"id":"de0fac71-bf7f-4196-8126-d612805df08f","name":"Send Interview Invite Email","type":"n8n-nodes-base.emailSend","position":[1860,1360],"webhookId":"92dfdc70-ac6d-468d-ae75-fb2c42b8a554","parameters":{},"typeVersion":2.1},{"id":"74f4cffe-d362-4aa6-984a-67dca1479186","name":"Send Assessment Failed Email","type":"n8n-nodes-base.emailSend","position":[2080,1440],"webhookId":"92dfdc70-ac6d-468d-ae75-fb2c42b8a554","parameters":{},"typeVersion":2.1},{"id":"97383a17-8065-453c-8399-e8481a6608ac","name":"Send Interview Cancelled Email","type":"n8n-nodes-base.emailSend","position":[2260,1600],"webhookId":"92dfdc70-ac6d-468d-ae75-fb2c42b8a554","parameters":{},"typeVersion":2.1},{"id":"b2735319-d17a-4eed-9385-412a1df5725c","name":"Interview Reschedule Invite Email","type":"n8n-nodes-base.emailSend","position":[2120,1740],"webhookId":"92dfdc70-ac6d-468d-ae75-fb2c42b8a554","parameters":{},"typeVersion":2.1},{"id":"c343af76-bf0c-436d-9d07-06a2049b99fe","name":"Send Interview Passed/Shortlisted Email","type":"n8n-nodes-base.emailSend","position":[1980,1860],"webhookId":"92dfdc70-ac6d-468d-ae75-fb2c42b8a554","parameters":{},"typeVersion":2.1},{"id":"9fac2c36-bcec-4a40-a68e-0d359fa1ebf8","name":"Send Interview Failed Email","type":"n8n-nodes-base.emailSend","position":[1800,1960],"webhookId":"92dfdc70-ac6d-468d-ae75-fb2c42b8a554","parameters":{},"typeVersion":2.1},{"id":"5fb01de0-215b-4d6f-ab4a-b7414c5ad24c","name":"No Operation, do nothing","type":"n8n-nodes-base.noOp","position":[880,780],"parameters":{},"typeVersion":1},{"id":"1e5241e3-cc08-487d-a82d-b8005fb73091","name":"Sticky Note16","type":"n8n-nodes-base.stickyNote","position":[0,1200],"parameters":{"content":""},"typeVersion":1},{"id":"6ed12099-5d4d-41d5-884d-c1e3723e877c","name":"Sticky Note18","type":"n8n-nodes-base.stickyNote","position":[140,1840],"parameters":{"content":""},"typeVersion":1},{"id":"636939ce-caef-4a1c-918b-5dffd681b941","name":"Sticky Note19","type":"n8n-nodes-base.stickyNote","position":[1060,1200],"parameters":{"content":""},"typeVersion":1},{"id":"e6227def-3091-4b16-a573-dbe12a02d68a","name":"Sticky Note20","type":"n8n-nodes-base.stickyNote","position":[-560,140],"parameters":{"content":""},"typeVersion":1},{"id":"fc0eabbb-0cfe-49fd-9fef-ff6d6afd4681","name":"Update Applicant's Status as RESUME SELECTED","type":"n8n-nodes-base.googleSheets","position":[3240,500],"parameters":{},"typeVersion":4.5}],"pinData":{},"connections":{"OpenAI":{"ai_languageModel":[[{"node":"Applicant's Details","type":"ai_languageModel","index":0},{"node":"Summarize Applicant's Profile","type":"ai_languageModel","index":0},{"node":"Semantic Fit & Evaluation by HR Expert","type":"ai_languageModel","index":0},{"node":"Summarize Job Role Description","type":"ai_languageModel","index":0}]]},"Extract from File":{"main":[[{"node":"Add Applicant's Details in Google Sheet","type":"main","index":0}]]},"On form submission":{"main":[[{"node":"Upload CV","type":"main","index":0},{"node":"Extract from File","type":"main","index":0}]]},"Applicant's Details":{"main":[[{"node":"Summarize Applicant's Profile","type":"main","index":0}]]},"Run Daily at 09:00 AM":{"main":[[{"node":"Fetch Records with Status \"Resume Selected\"","type":"main","index":0}]]},"Get Assessment Form URL":{"main":[[{"node":"Send Assessment Submission Email","type":"main","index":0}]]},"Structured Output Parser":{"ai_outputParser":[[{"node":"Semantic Fit & Evaluation by HR Expert","type":"ai_outputParser","index":0}]]},"Approval Check - IF Condition":{"main":[[{"node":"Update Applicant's Status as RESUME SELECTED","type":"main","index":0}],[{"node":"Update Applicant's Status as REJECTED","type":"main","index":0}]]},"Route actions based on Status":{"main":[[{"node":"Send Interview Invite Email","type":"main","index":0}],[{"node":"Send Assessment Failed Email","type":"main","index":0}],[],[{"node":"Send Interview Cancelled Email","type":"main","index":0}],[{"node":"Interview Reschedule Invite Email","type":"main","index":0}],[{"node":"Send Interview Passed/Shortlisted Email","type":"main","index":0}],[{"node":"Send Interview Failed Email","type":"main","index":0}]]},"Summarize Applicant's Profile":{"main":[[{"node":"Get Job Description from Google Sheets","type":"main","index":0}]]},"Summarize Job Role Description":{"main":[[{"node":"Semantic Fit & Evaluation by HR Expert","type":"main","index":0}]]},"Notify TA for Approval via Email":{"main":[[{"node":"Approval Check - IF Condition","type":"main","index":0}]]},"Send Assessment Submission Email":{"main":[[{"node":"Update Status to Assessment Sent","type":"main","index":0}]]},"Update Status to Assessment Sent":{"main":[[{"node":"Loop to Send Assessment Link to Each Candidate","type":"main","index":0}]]},"Update Applicant's Status as REJECTED":{"main":[[{"node":"Send Rejection Email to Candidate","type":"main","index":0}]]},"Get Job Description from Google Sheets":{"main":[[{"node":"Summarize Job Role Description","type":"main","index":0}]]},"Semantic Fit & Evaluation by HR Expert":{"main":[[{"node":"Update Evaluation Results in Google Sheets","type":"main","index":0}]]},"Add Applicant's Details in Google Sheet":{"main":[[{"node":"Applicant's Details","type":"main","index":0}]]},"Update Evaluation Results in Google Sheets":{"main":[[{"node":"Notify TA for Approval via Email","type":"main","index":0}]]},"Fetch Records with Status \"Resume Selected\"":{"main":[[{"node":"Loop to Send Assessment Link to Each Candidate","type":"main","index":0}]]},"Technical Project Manager Assessment Trigger":{"main":[[{"node":"Update Applicant Status to Assessment Submitted","type":"main","index":0}]]},"Update Applicant's Status as RESUME SELECTED":{"main":[[{"node":"Send Shortlist Email to Candidate","type":"main","index":0}]]},"Technical Support Engineer Assessment Trigger":{"main":[[{"node":"Update Applicant Status to Assessment Submitted","type":"main","index":0}]]},"Loop to Send Assessment Link to Each Candidate":{"main":[[{"node":"No Operation, do nothing","type":"main","index":0}],[{"node":"Get Assessment Form URL","type":"main","index":0}]]},"Update Applicant Status to Assessment Submitted":{"main":[[{"node":"Notify TA via Email for Assessment Submission","type":"main","index":0},{"node":"Notify TA via Slack for Assessment Submission","type":"main","index":0}]]},"Trigger when Interview booked by applicant in calendly":{"main":[[{"node":"Update Status to Interview Booked","type":"main","index":0}]]},"Get Triggered when Applicant Status Update in Google Sheet":{"main":[[{"node":"Route actions based on Status","type":"main","index":0}]]}}}


name: Build an Image Restoration Service with n8n & Gemini AI Image Editing
author_name: Jimleuk
author_username: jimleuk
nodes_used: ["n8n-nodes-base.httpRequest","n8n-nodes-base.googleDrive"]
categories: []
created_at: 2025-06-09T12:56:20.236Z
updated_at: 2025-06-09T12:56:20.236Z
url: https://n8n.io/workflows/4815
scraped_at: 2025-06-19 22:48:59
description:
  This n8n template demonstrates how to build a simple but effective vintage image restoration service using an AI model with image editing capabilities.

  With Gemini now capable of multimodal output, it's a great time to explore this capability for image or graphics automation. Let's see how well it does for a task such as image restoration.

  Good to know
  At time of writing, each image generated will cost $0.039 USD. See Gemini Pricing for updated info.
  The model used in this workflow is geo-restricted! If it says model not found, it may not be available in your country or region.

  How it works
  Images are imported into our workflow via the HTTP node and converted to base64 strings using the Extract from file node.
  The image data is then pipelined to Gemini's Image Generation model. A prompt is provided to instruct Gemini to "restore" the image to near new condition - of course, feel free to experiment with this prompt to improve the results!
  Gemini's responds with the image as a base64 string and hence, a convert to file node is used to transform the data to binary.
  With the restored image as a binary, we can then use this with our Google Drive node to upload it to our desired folder.

  How to use
  This demonstration uses 3 random images sourced from the internet but any typical image file will work.
  Use a webhook node to allow integration from other applications.
  Use a telegram trigger for instant mobile service!

  Requirements
  Google Gemini for LLM/Image generation
  Google Drive for Upload Storage

  Customising this workflow
  AI image editing can be applied to many use-cases not just image restoration. Try using it to add watermarks, branding or modify an existing image for marketing purposes.

workflow_json:
  {"meta":{"instanceId":"408f9fb9940c3cb18ffdef0e0150fe342d6e655c3a9fac21f0f644e8bedabcd9","templateCredsSetupCompleted":true},"nodes":[{"id":"b6a5c37d-b845-4fd2-8ea3-db23aed99286","name":"When clicking ‘Execute workflow’","type":"n8n-nodes-base.manualTrigger","position":[-80,320],"parameters":{},"typeVersion":1},{"id":"1f363fc5-42cf-4e9c-ae74-496030362ed9","name":"Sample Images","type":"n8n-nodes-base.set","position":[120,320],"parameters":{"options":{},"assignments":{"assignments":[{"id":"7196d08d-dff6-48e4-a06d-0ec863a4dff3","name":"url","type":"array","value":"={{\n[\n  \"https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/l8b3j1sf6ejx73z0awsh\",\n  \"https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/htrjbmiozdrvxwdsreyt\",\n  \"https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/ykftgxpozp2pr4sxpuoy\"\n]\n}}"}]}},"typeVersion":3.4},{"id":"e078aba0-2f2b-47b5-90b2-c457184e6237","name":"Split Out","type":"n8n-nodes-base.splitOut","position":[320,320],"parameters":{"options":{},"fieldToSplitOut":"url"},"typeVersion":1},{"id":"a0fbf72b-d079-4777-be06-531e0e131857","name":"Download Image","type":"n8n-nodes-base.httpRequest","position":[520,320],"parameters":{"url":"={{ $json.url }}","options":{}},"typeVersion":4.2},{"id":"77f0d0c7-e6bd-4f15-beff-9cb53446fcb0","name":"Gemini Image Restoration","type":"n8n-nodes-base.httpRequest","position":[1100,320],"parameters":{"url":"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-preview-image-generation:generateContent","method":"POST","options":{},"jsonBody":"={\n  \"contents\": [\n    {\n      \"parts\": [\n        {\n          \"text\": \"You are an vintage image restoration agent. Restore the given image by removing cracks and tears and fill in missing sections of the image. Retain the dimensions, colors and camera film type of the original image.\"\n        },\n        {\n          \"inline_data\": {\n            \"mime_type\": \"{{ $('Download Image').item.binary.data.mimeType }}\",\n            \"data\": \"{{ $json.data }}\"\n          }\n        }\n      ]\n    }\n  ],\n  \"generationConfig\": {\n    \"responseModalities\": [\n      \"TEXT\",\n      \"IMAGE\"\n    ]\n  }\n}","sendBody":true,"specifyBody":"json","authentication":"predefinedCredentialType","nodeCredentialType":"googlePalmApi"},"credentials":{"googlePalmApi":{"id":"dSxo6ns5wn658r8N","name":"Google Gemini(PaLM) Api account"}},"typeVersion":4.2},{"id":"6aebcc29-a65d-4cb9-8d6a-56f24b58c7f5","name":"Extract from File","type":"n8n-nodes-base.extractFromFile","position":[720,320],"parameters":{"options":{},"operation":"binaryToPropery"},"typeVersion":1},{"id":"1c50d319-1771-408f-9015-f04bb6a3d305","name":"Get Image Contents","type":"n8n-nodes-base.set","position":[1340,320],"parameters":{"options":{},"assignments":{"assignments":[{"id":"021aad70-de11-4387-844e-7e7dfd3b1044","name":"image","type":"string","value":"={{ $json.candidates[0].content.parts.find(part => part.inlineData).inlineData.data }}"},{"id":"62877ef7-2057-4d35-a44b-1d58fa1f1769","name":"mimeType","type":"string","value":"={{ $json.candidates[0].content.parts.find(part => part.inlineData).inlineData.mimeType }}"}]}},"typeVersion":3.4},{"id":"c19074f0-45a1-42bd-b25f-966f26ef5ef5","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[2220,-200],"parameters":{"width":700,"height":320,"content":"|Original|Restored|\n|-|-|\n|![](https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/l8b3j1sf6ejx73z0awsh)|![](https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/wvmeua6tpkvxiqcd6gpf)|"},"typeVersion":1},{"id":"82e82d53-e5ff-44a2-96ca-1867058fbb65","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-140,80],"parameters":{"color":7,"width":1060,"height":460,"content":"## 1. Download Sample Images\n[Read more about the HTTP Request node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.httprequest/)\n\nFor this demonstration, we'll download 3 sample vintage photographs. These images show a variety of damage such as cracks, tears and missing or obscured sections and it will be the goal of this workflow to automate the restoration.\n\nInstead of a manual trigger, use a webhook trigger instead to integrate it into apps!"},"typeVersion":1},{"id":"eb1f70d5-2d3f-4f22-badb-d49569f565c2","name":"Upload to Drive","type":"n8n-nodes-base.googleDrive","position":[1960,320],"parameters":{"name":"=file_restored_{{ $itemIndex }}.{{ $binary.data.fileExtension }}","driveId":{"__rl":true,"mode":"list","value":"My Drive"},"options":{},"folderId":{"__rl":true,"mode":"list","value":"root","cachedResultName":"/ (Root folder)"}},"credentials":{"googleDriveOAuth2Api":{"id":"yOwz41gMQclOadgu","name":"Google Drive account"}},"typeVersion":3},{"id":"4f980d9d-a993-4ec6-80fd-1a323e40822d","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[960,80],"parameters":{"color":7,"width":620,"height":460,"content":"## 2. Use Gemini LLM to Restore Damaged Images\n[Read more about Gemini's Text and Image to Image Editing](https://ai.google.dev/gemini-api/docs/image-generation#gemini-image-editing)\n\nText-and-image-to-image capability enables LLMs to become instant replacements for a lot of image and photo editing applications. Here, we can use Gemini's new Image Generation model to restore vintage photos by removing damage and filling in missing sections."},"typeVersion":1},{"id":"69f7f355-5443-4265-b2a1-901711fa93dd","name":"Convert to File","type":"n8n-nodes-base.convertToFile","onError":"continueRegularOutput","position":[1720,320],"parameters":{"options":{"mimeType":"={{ $json.mimeType }}"},"operation":"toBinary","sourceProperty":"image"},"typeVersion":1.1},{"id":"beae9111-8186-4afd-9fa6-c732f0229854","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1620,80],"parameters":{"color":7,"width":560,"height":460,"content":"## 3. Upload to Google Drive\n[Read more about Google Drive node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.googledrive)\n\nGemini outputs the image data as a base64 string so conversion to binary is sometimes necessary such as when uploading to Google Drive. We're using Google drive here but you can upload to any destination of your choosing."},"typeVersion":1},{"id":"00aaa458-1c49-4adf-87d6-ea70309107f9","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-640,-380],"parameters":{"width":460,"height":920,"content":"## Try It Out!\n### This n8n template demonstrates how to build a simple but effective vintage image restoration service using an AI model with image editing capabilities.\n\nWith Gemini now capable of multimodal output, it's a great time to explore this capability for image or graphics automation. Let's see how well it does for a task such as image restoration.\n\n**Please note, at time of writing each image generated will cost $0.039 USD**. See Gemini Pricing for updated info.\n\n### How it works\n* Images are imported into our workflow via the HTTP node and converted to base64 strings using the Extract from file node.\n* The image data is then pipelined to Gemini's Image Generation model. A prompt is provided to instruct Gemini to \"restore\" the image to near new condition - of course, feel free to experiment with this prompt to improve the results!\n* Gemini's responds with the image as a base64 string and hence, a convert to file node is used to transform the data to binary.\n* With the restored image as a binary, we can then use this with our Google Drive node to upload it to our desired folder.\n\n### How to use\n* This demonstration uses 3 random images sourced from the internet but any typical image file will work.\n* Use a webhook node to allow integration from other applications.\n* Use a telegram trigger for instant mobile service!\n\n### Requirements\n* Google Gemini for LLM/Image generation\n* Google Drive for Upload Storage\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":"4e4b822b-983b-48d2-a319-68242b7af171","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[-640,580],"parameters":{"color":5,"width":460,"height":140,"content":"### Geo Restrictions!\nPlease note at time of writing, the Gemini Image Generation model is restricted to certain countries and regions. If you're getting model not found errors, it's possible the model may not be available in your country!"},"typeVersion":1},{"id":"24d74843-d9b5-4302-8136-159e0a7dd492","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[2220,140],"parameters":{"width":400,"height":440,"content":"|Original|Restored|\n|-|-|\n|![](https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/htrjbmiozdrvxwdsreyt)|![](https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/ibm69t8gzcqqywrruioi)|"},"typeVersion":1},{"id":"f77ed90e-70ca-4268-9c77-17e49f94a4bb","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[2640,140],"parameters":{"width":580,"height":300,"content":"|Original|Restored|\n|-|-|\n|![](https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/ykftgxpozp2pr4sxpuoy)|![](https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/iah4qyu1xpiqwgl9sbg8)|"},"typeVersion":1}],"pinData":{},"connections":{"Split Out":{"main":[[{"node":"Download Image","type":"main","index":0}]]},"Sample Images":{"main":[[{"node":"Split Out","type":"main","index":0}]]},"Download Image":{"main":[[{"node":"Extract from File","type":"main","index":0}]]},"Convert to File":{"main":[[{"node":"Upload to Drive","type":"main","index":0}]]},"Extract from File":{"main":[[{"node":"Gemini Image Restoration","type":"main","index":0}]]},"Get Image Contents":{"main":[[{"node":"Convert to File","type":"main","index":0}]]},"Gemini Image Restoration":{"main":[[{"node":"Get Image Contents","type":"main","index":0}]]},"When clicking ‘Execute workflow’":{"main":[[{"node":"Sample Images","type":"main","index":0}]]}}}


name: AI-Powered Local Event Finder with Multi-Tool Search
author_name: Jez
author_username: jez
categories: []
created_at: 2025-06-09T12:59:58.555Z
updated_at: 2025-06-09T12:59:58.555Z
url: https://n8n.io/workflows/4816
scraped_at: 2025-06-19 22:50:32
description:
  Summary
  This n8n workflow implements an AI-powered "Local Event Finder" agent. It takes user criteria (like event type, city, date, and interests), uses a suite of search tools (Brave Web Search, Brave Local Search, Google Gemini Search) and a web scraper (Jina AI) to find relevant events, and returns formatted details. The entire agent is exposed as a single, easy-to-use MCP (Multi-Capability Peer) tool, making it simple to integrate into other workflows or applications.

  This template cleverly combines the MCP server endpoint and the AI agent logic into a single n8n workflow file for ease of import and management.

  Key Features
  Intelligent Multi-Tool Search:** Dynamically utilizes web search, precise local search, and advanced Gemini semantic search to find events.
  Detailed Information via Web Scraping:** Employs Jina AI to extract comprehensive details directly from event web pages.
  Simplified MCP Tool Exposure:** Makes the complex event-finding logic available as a single, callable tool for other MCP-compatible clients (e.g., Roo Code, Cline, other n8n workflows).
  Customizable AI Behavior:** The core AI agent's behavior, tool usage strategy, and output formatting can be tailored by modifying its System Prompt.
  Modular Design:** Uses distinct nodes for LLM, memory, and each external tool, allowing for easier modification or extension.

  Benefits
  Simplifies Client-Side Integration:** Offloads the complexity of event searching and data extraction from client applications.
  Provides Richer Event Data:** Goes beyond simple search links to extract and format key event details.
  Flexible & Adaptable:** Can be adjusted to various event search needs and can incorporate new tools or data sources.
  Efficient Processing:** Leverages specialized tools for different aspects of the search process.

  Nodes Used
  MCP Trigger
  Tool Workflow
  Execute Workflow Trigger
  AI Agent
  Google Gemini Chat Model (ChatGoogleGenerativeAI)
  Simple Memory (Window Buffer Memory)
  MCP Client (for Brave Search tools via Smithery)
  Google Gemini Search Tool
  Jina AI Tool

  Prerequisites
  An active n8n instance.
  Google AI API Key:** For the Gemini LLM (Google Gemini Chat Model node) and the Google Gemini Search Tool. Ensure your key is enabled for these services.
  Jina AI API Key:** For the jina_ai_web_page_scraper node. A free tier is often available.
  Access to a Brave Search MCP Provider (Optional but Recommended):**
      This template uses MCP Client nodes configured for Brave Search via a provider like Smithery. You'll need an account/API key for your chosen Brave Search MCP provider to configure the smithery brave search credential.
      Alternatively, you could adapt these to call Brave Search API directly if you manage your own access, or replace them with other search tools.

  Setup Instructions
  Import Workflow: Download the JSON file for this template and import it into your n8n instance.
  Configure Credentials:
      Google Gemini LLM:
          Locate the Google Gemini Chat Model node.
          Select or create a "Google Gemini API" credential (named Google Gemini Context7 in the template) using your Google AI API Key.
      Google Gemini Search Tool:
          Locate the google_gemini_event_search node.
          Select or create a "Gemini API" credential (named Gemini Credentials account in the template) using your Google AI API Key (ensure it's enabled for Search/Vertex AI).
      Jina AI Web Scraper:
          Locate the jina_ai_web_page_scraper node.
          Select or create a "Jina AI API" credential (named Jina AI account in the template) using your Jina AI API Key.
      Brave Search (via MCP):
          You'll need an MCP Client HTTP API credential to connect to your Brave Search MCP provider (e.g., Smithery).
          Create a new "MCP Client HTTP API" credential in n8n. Name it, for example, smithery brave search.
          Configure it with the Base URL and any required authentication (e.g., API key in headers) for your Brave Search MCP provider.
          Locate the brave_web_search and brave_local_search MCP Client nodes in the workflow.
          Assign the smithery brave search (or your named credential) to both of these nodes.
  Activate Workflow: Ensure the workflow is active.
  Note MCP Trigger Path:
      Locate the local_event_finder (MCP Trigger) node.
      The Path field (e.g., 0ca88864-ec0a-4c27-a7ec-e28c5a900697) combined with your n8n webhook base URL forms the endpoint for client calls.
      Example Endpoint: YOUR_N8N_INSTANCE_URL/webhooks/PATH-TO-MCP-SERVER

  Customization
  AI Behavior:** Modify the "System Message" parameter within the event_finder_agent node to change the AI's persona, its strategy for using tools, or the desired output format.
  LLM Model:** Swap the Google Gemini Chat Model node with another compatible LLM node (e.g., OpenAI Chat Model) if desired. You'll need to adjust credentials and potentially the system prompt.
  Tools:** Add, remove, or replace tool nodes (e.g., use a different search provider, add a weather API tool) and update the event_finder_agent's system prompt and tool configuration accordingly.
  Scraping Depth:** Be mindful of the jina_ai_web_page_scraper's usage due to potential timeouts. The system prompt already guides the LLM on this, but you can adjust its usage instructions.

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

workflow_json:
  {"id":"jzyBdgtZyvqzRcus","meta":{"instanceId":"3612a0c89f35a354ddd1216385240db51b4635fde7cae2a0d5004be915b832f3","templateCredsSetupCompleted":true},"name":"Local Event Finder","tags":[],"nodes":[{"id":"3896a94e-9d40-4bb7-a333-cce2bae94e33","name":"Google Gemini Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatGoogleGemini","position":[-40,1560],"parameters":{"options":{},"modelName":"models/gemini-2.5-flash-preview-05-20"},"credentials":{"googlePalmApi":{"id":"c8jj7D6oz6RJ81qp","name":"Google Gemini Context7"}},"typeVersion":1},{"id":"15dba0b1-3f9b-4ed4-9efe-f8be50da710b","name":"Simple Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[820,1620],"parameters":{"sessionKey":"={{ $execution.id }}","sessionIdType":"customKey"},"typeVersion":1.3},{"id":"83c73d4e-f4ae-4618-9ab4-0bcc05339395","name":"brave_web_search","type":"n8n-nodes-mcp.mcpClientTool","position":[1160,1300],"parameters":{"toolName":"brave_web_search","operation":"executeTool","connectionType":"http","toolParameters":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Tool_Parameters', `Generate a JSON object with the parameters for the 'brave_web_search' tool.\nThe tool expects a JSON object with the following keys:\n- \"query\": (string, **required**) The search terms for the web search.\n- \"count\": (number, optional) The number of results to return per page. Maximum is 20. If not provided, a default value will be used by the service.\n- \"offset\": (number, optional) The pagination offset to retrieve a specific page of results. Maximum is 9. If not provided, the first page is returned.\n\nExample (required only):\n{\"query\": \"latest AI research\"}\n\nExample (with optionals):\n{\"query\": \"popular javascript frameworks\", \"count\": 10, \"offset\": 0}`, 'json') }}","descriptionType":"manual","toolDescription":"Performs a general web search using Brave Search. Ideal for finding event listings, articles, official event websites, or when a broader search beyond a specific immediate locality is necessary. Use for queries like 'music festivals [country] [month]' or 'tech conferences [year]'. Parameters: 'query' (required string), 'count' (optional number, max 20), 'offset' (optional number, max 9 for pagination)."},"credentials":{"mcpClientHttpApi":{"id":"izP58157WoLmqx5y","name":"smithery brave search"}},"typeVersion":1},{"id":"8ba5272c-d95b-48e3-b48d-0f6bedcdad5c","name":"brave_local_search","type":"n8n-nodes-mcp.mcpClientTool","position":[1720,1300],"parameters":{"toolName":"brave_local_search","operation":"executeTool","connectionType":"http","toolParameters":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Tool_Parameters', `Generate a JSON object with the parameters for the 'brave_local_search' tool.\nThe tool expects a JSON object with the following keys:\n- \"query\": (string, **required**) The search terms for the local search (e.g., \"coffee shop downtown\", \"bookstore [zip code]\").\n- \"count\": (number, optional) The number of local results to return. Maximum is 20. If not provided, a default value will be used by the service.\n\nExample (required only):\n{\"query\": \"restaurants near Eiffel Tower\"}\n\nExample (with optional count):\n{\"query\": \"best parks in Berlin\", \"count\": 5}\n\nNote: This tool does not support an 'offset' parameter for pagination. It may fall back to web search if no local results are found.`, 'json') }}","descriptionType":"manual","toolDescription":"Searches for local events, venues, and points of interest using Brave Local Search. Best for queries targeting a specific city or area, like 'live music in [City Name] this weekend' or 'art workshops near [Address/Zip Code]'. May fall back to a general web search if no specific local results are found. Parameters: 'query' (required string), 'count' (optional number, max 20)."},"credentials":{"mcpClientHttpApi":{"id":"izP58157WoLmqx5y","name":"smithery brave search"}},"typeVersion":1},{"id":"9be2f212-43d9-4e31-a090-3b3e44195291","name":"find_events","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[-60,320],"parameters":{"workflowId":{"__rl":true,"mode":"list","value":"jzyBdgtZyvqzRcus","cachedResultName":"Local Event Finder"},"description":"=This tool initiates a detailed search for local events. It gathers specific user requirements such as the type of event, preferred city and country, desired date range, and related interests. These inputs are then passed to an internal workflow to find and return matching event information.","workflowInputs":{"value":{"city":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('city', `The primary city where the user wishes to find events. This should be a specific city name. Examples: 'Perth', 'Berlin', 'Tokyo'.`, 'string') }}","query":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('query', `A specific search phrase or natural language description detailing the event(s) the user is looking for. Examples: 'outdoor jazz concerts', 'weekend food and wine festivals', 'mountain biking and craft beer gatherings'.`, 'string') }}","country":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('country', `The country corresponding to the specified city, to help narrow the search geographically. Examples: 'Australia', 'Germany', 'Japan'.`, 'string') }}","interests":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('interests', `A comma-separated list of user interests or keywords that help further refine the event search, complementing the main 'query'. Examples: 'live music, craft beer, hiking', 'technology, AI, startups', 'family activities, educational, outdoor'.`, 'string') }}","date-range":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('date-range', `The desired timeframe for the events. This can be specific (e.g., 'July 15-20, 2025'), general (e.g., 'July 2025', 'next weekend'), or a season (e.g., 'Summer 2025'). The more specific, the better.`, 'string') }}"},"schema":[{"id":"query","type":"string","display":true,"removed":false,"required":false,"displayName":"query","defaultMatch":false,"canBeUsedToMatch":true},{"id":"city","type":"string","display":true,"removed":false,"required":false,"displayName":"city","defaultMatch":false,"canBeUsedToMatch":true},{"id":"country","type":"string","display":true,"removed":false,"required":false,"displayName":"country","defaultMatch":false,"canBeUsedToMatch":true},{"id":"date-range","type":"string","display":true,"removed":false,"required":false,"displayName":"date-range","defaultMatch":false,"canBeUsedToMatch":true},{"id":"interests","type":"string","display":true,"removed":false,"required":false,"displayName":"interests","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.2},{"id":"c1becac0-c6a1-4a2f-be3b-c69b7cb5a69a","name":"even_finder_workflow","type":"n8n-nodes-base.executeWorkflowTrigger","position":[-500,1180],"parameters":{"workflowInputs":{"values":[{"name":"query"},{"name":"city"},{"name":"country"},{"name":"date-range"},{"name":"interests"}]}},"typeVersion":1.1},{"id":"fbec2433-db9a-43db-b143-551c624ee085","name":"event_finder_agent","type":"@n8n/n8n-nodes-langchain.agent","position":[240,1180],"parameters":{"text":"=Find relevant events based on the provided user profile and preferences.","options":{"systemMessage":"=You are a specialized Local Event Finder assistant. Your mission is to discover relevant events tailored to user preferences and present them in a clear, engaging markdown format.\n\n**User Preferences to Consider:**\n*   **Query:** {{ $('even_finder_workflow').item.json.query }}\n*   **City:** {{ $('even_finder_workflow').item.json.city }}\n*   **Country:** {{ $('even_finder_workflow').item.json.country }}\n*   **Date Range:** {{ $('even_finder_workflow').item.json.date-range }}\n*   **Interests:** {{ $('even_finder_workflow').item.json.interests }}\n\n**Your Operational Protocol:**\n\n1.  **Event Discovery Goal:**\n    *   Identify 1 to 5 events that closely match all provided user criteria.\n    *   Focus on quality and relevance over quantity.\n\n2.  **Location Search Strategy:**\n    *   **Primary Focus:** The specified `City`.\n    *   **Secondary Search:** If results are sparse, expand to nearby cities or statewide within the `Country`.\n    *   **Tertiary Search (Optional):** For exceptionally fitting events based on interests, consider the nearest capital city or other major capital cities in the `Country`.\n\n3.  **Tool Usage Guidelines:**\n    *   **`brave_local_search`**: Use this first for precise, location-based queries (e.g., \"live music in {{ $('even_finder_workflow').item.json.city }} this weekend\").\n    *   **`brave_web_search`**: Employ for broader event searches, finding event listings, or if local search is insufficient (e.g., \"mountain biking events {{ $('even_finder_workflow').item.json.country }} in {{ $('even_finder_workflow').item.json.date-range }}\").\n    *   **`google_gemini_event_search`**: Utilize for more complex queries, combining multiple interests, or as a powerful alternative if other searches are not fruitful. This tool can help synthesize information and understand nuanced requests.\n    *   **`jina_ai_web_page_scraper`**: After identifying promising event URLs from search results, use this tool to extract detailed information directly from the event pages.\n        *   **Critical Usage Note:** Due to a 60-second MCP server timeout (as of June 2025), use `jina_ai_web_page_scraper` very selectively. Scrape a maximum of 1-2 essential URLs per event discovery session to avoid timeouts. Prioritize official event pages.\n\n4.  **Information Extraction per Event:**\n    For each recommended event, strive to find and include:\n    *   Event Name\n    *   Date(s) and Time(s)\n    *   Full Location Address/Venue Name\n    *   A concise and engaging Description\n    *   Official Event Link (highly preferred)\n    *   Booking/Ticket Link (if available and distinct from the event link)\n\n5.  **Response Formatting:**\n    *   Present your findings in well-structured markdown.\n    *   Use headings (e.g., `##`), bullet points (`*`), bolding (`**text**`), and relevant emojis to enhance readability and visual appeal.\n    *   Clearly separate information for each event.\n\n6.  **Handling No Results:**\n    *   If, after a thorough search (including expanded location criteria), no suitable events are found, clearly and politely inform the user.\n\n**Example Structure for a Single Event in Your Response:**\n\n---\n🎉 **[Event Name]** 🎉\n*   **📅 Date & Time:** [Event Date(s)], [Event Time(s)]\n*   **📍 Location:** [Venue Name, Full Address, City]\n*   **📝 Description:** [A brief, enticing summary of what the event offers and how it matches user interests.]\n*   **🔗 Event Link:** [Link to Official Event Page]\n*   **🎟️ Booking Link:** [Link to Booking/Tickets, if available]\n---\n\nPrioritize accuracy, relevance, and the direct usability of the information provided. Ensure any links are functional."},"promptType":"define"},"typeVersion":2},{"id":"2cb94f37-21fc-48d7-8661-3d3270bae356","name":"local_event_finder","type":"@n8n/n8n-nodes-langchain.mcpTrigger","position":[-220,-80],"webhookId":"0ca88864-ec0a-4c27-a7ec-e28c5a900697","parameters":{"path":"0ca88864-ec0a-4c27-a7ec-e28c5a900697"},"typeVersion":1},{"id":"a8afc19d-8394-4e4d-bd6a-047e665b5a68","name":"google_gemini_event_search","type":"n8n-nodes-gemini-search.geminiSearchToolTool","position":[2300,1300],"parameters":{"model":"gemini-2.5-flash-preview-05-20","query":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Query', `Formulate a concise and effective search query for finding events. Combine the user's primary query, interests, desired location (city/country), and date range. Focus on keywords that an advanced search engine like Gemini can use to find specific event listings or relevant information. Example: \"family-friendly music festivals Perth Australia July 2025\" or \"tech conferences with AI workshops Berlin next quarter\".`, 'string') }}","options":{"extractSourceUrl":true},"organization":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Organization_Context', `(Optional) Provide any specific organizational context that might help refine the event search. This could relate to the type of organizations hosting the events (e.g., 'community groups', 'official city event organizers', 'universities') or a broader theme. Only use if a specific context is likely to improve results, otherwise leave blank or provide a general statement like 'public events'.`, 'string') }}","restrictUrls":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Restrict_Search_to_URLs', `(Optional) Provide a comma-separated list of specific website URLs if the search should be restricted to known, trusted sources (e.g., official tourism sites, major event listing platforms for the region). Use this sparingly and only when confident that the desired events are likely to be found on those specific sites. Example: 'cityofperth.events.wa.gov.au, eventbrite.com.au'. Leave blank to search the broader web.`, 'string') }}","toolDescription":"Leverages Google's Gemini model for advanced, context-aware event searching. Use this for complex queries, combining multiple interests (e.g., 'family-friendly outdoor art festivals in [Region] during [Month] with accessibility options'), or when other search tools need a more nuanced understanding. Can extract source URLs. Key Parameters: 'query' (string), 'organization' (string, for context), 'restrictUrls' (string, for specific sites)."},"credentials":{"geminiSearchApi":{"id":"grHOyabfaEb2A17I","name":"Gemini Credentials account"}},"typeVersion":1},{"id":"5f733091-c9b0-4dd8-90f0-9eee8af122dd","name":"jina_ai_web_page_scraper","type":"n8n-nodes-base.jinaAiTool","position":[2880,1300],"parameters":{"url":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('URL', `Provide the full, direct URL of a web page that contains detailed information about a specific event. This URL should ideally be an official event page or a highly relevant listing page that was identified by a previous search step (e.g., from brave_web_search or google_gemini_event_search). Ensure the URL is valid and points to the content you want to extract. Example: 'https://example.com/events/specific-event-details'. Remember to use this tool sparingly (max 1-2 URLs per workflow run) due to potential timeouts.`, 'string') }}","options":{"outputFormat":"markdown","enableImageCaptioning":true},"requestOptions":{},"descriptionType":"manual","toolDescription":"Extracts and summarizes the main textual content from a given web page URL, returning it in markdown format. Use this to get detailed information (like descriptions, schedules, specific features) from event pages identified by search tools. Parameter: 'url' (required string). Critical: Use sparingly (1-2 URLs max) due to execution time limits."},"credentials":{"jinaAiApi":{"id":"Ds8w0d9HhKCi6twc","name":"Jina AI account"}},"typeVersion":1},{"id":"48198d3f-6c86-4b95-a0f2-a04eac3d8c36","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[860,-900],"parameters":{"color":7,"width":760,"height":320,"content":"## 📞 MCP Client Configuration\n\nExternal clients (like other n8n workflows, Roo Code, or Cline) configure this agent as a tool.\n\n**Example Client Tool Configuration (e.g., for Roo Code/Cline):**\n```json\n\"local-event-finder\": {\n      \"url\": \"https://YOUR-MCP-HOST/mcp/YOUR-MCP-SERVER-PATH/sse\",\n      \"alwaysAllow\": [\n        \"find_events\"\n      ],\n      \"timeout\": 3600\n    }"},"typeVersion":1},{"id":"50d4814b-eee3-46be-bdc5-2d730872b34d","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-860,-320],"parameters":{"color":4,"width":840,"height":320,"content":"## 📡 local_event_finder (MCP Server Trigger)\n\n🚪 **Entry Point for External Calls**\n*   **Purpose:** Receives requests from external clients to use the \"Local Event Finder\" agent.\n*   **Function:** Listens for HTTP POST requests formatted for MCP.\n*   **Tool Exposed:** Exposes the `find_events` tool capability.\n*   **Typical Input:** JSON payload containing `tool_name: \"find_events\"` and `tool_input` (with query, city, etc.).\n*   **Typical Output:** Passes the `tool_input` to the `find_events` (Tool Workflow) no"},"typeVersion":1},{"id":"71e54414-aa7c-4cab-b537-257ff762108f","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-860,60],"parameters":{"color":4,"width":840,"height":320,"content":"## ➡️ find_events (Tool Workflow Node)\n\n📞 **Invokes the Agent Logic**\n*   **Purpose:** This node acts as the bridge, formally calling the agent's core logic which, in this combined workflow, is triggered by the `even_finder_workflow` (Execute Workflow Trigger) node.\n*   **Action:** Calls the \"Local Event Finder\" workflow itself to execute the agent logic.\n*   **Inputs:** Receives `query`, `city`, `country`, `date-range`, `interests` from the MCP Trigger's parsed input.\n*   **Outputs:** Passes these inputs to the `even_finder_workflow` (Execute Workflow Trigger) node within this same workflow. The final output of the agent logic (from `event_finder_agent`) will be the result of this tool call."},"typeVersion":1},{"id":"e6b00332-ce68-4fce-8238-52e19c746445","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[860,-520],"parameters":{"color":7,"width":760,"height":320,"content":"## 🗺️ Main MCP Server Workflow Overview (Conceptual Area)\n\n**Agent Name:** Local Event Finder\n*   **Gateway Function:** This section of the workflow acts as an MCP (Multi-Capability Peer) Server, making the \"Local Event Finder\" AI agent accessible as a tool to other systems.\n*   **Trigger:** `local_event_finder` (MCP Trigger) receives external requests.\n*   **Tool Workflow Node:** `find_events` node packages the request and invokes the agent's core logic within this same workflow.\n*   **Data Flow:** External Request -> `local_event_finder` -> `find_events` -> `even_finder_workflow` (starts agent logic).\n*   **Pattern:** This setup demonstrates an n8n AI Agent exposed via an MCP Server. In this case, both server and agent logic reside in a single, self-contained workflow."},"typeVersion":1},{"id":"b87c9502-1805-435f-a922-e932dcdc11e7","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[1680,-1200],"parameters":{"color":3,"width":740,"height":240,"content":"## 📄 Workflow Information\n\n*   **Workflow Name:** Local Event Finder (acts as both MCP Server & Agent Logic)\n*   **Version:** 1.0.0\n*   **Last Updated:** 2025-06-09\n*   **👤 Author:** Jeremy Dawes, Jezweb ([www.jezweb.com.au](https://www.jezweb.com.au/))\n*   **Description:** This workflow serves as an MCP endpoint for the \"Local Event Finder\" AI agent. It receives requests, passes them to the agent logic, and returns the found events."},"typeVersion":1},{"id":"8974efe8-c3d2-43f4-a340-ee346ce08548","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[2480,-80],"parameters":{"color":2,"width":740,"height":420,"content":"## ✅ TODO / Future Enhancements (Main Area)\n\n*   [ ] Add more robust input validation.\n*   [ ] Implement more sophisticated error handling for MCP calls.\n*   [ ] Add rate limiting or API key authentication for external access.\n*   [ ] Consider splitting into separate Main (MCP) and Sub (Agent) workflow files for very complex scenarios.\n\n\n\n## ✅ TODO / Future Enhancements (Sub / Agent Logic Area)\n\n*   [ ] Implement more sophisticated tool selection logic (e.g., conditional routing).\n*   [ ] Add a tool to verify event dates or venue existence.\n*   [ ] Allow user to specify preferred search engines or data sources.\n*   [ ] Improve extraction of structured data from scraped pages.\n*   [ ] Offer summarization options for lengthy event descriptions."},"typeVersion":1},{"id":"f2b540c4-faff-41cc-be53-d0c885a52946","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-740,720],"parameters":{"color":4,"width":640,"height":520,"content":"## 🏁 Sub-Workflow Start: Local Event Finder Logic\n(Node: `even_finder_workflow` - Execute Workflow Trigger)\n\n🎬 **Kicks off the Agent's Thinking Process**\n*   **Purpose:** This is the internal entry point for the agent's core logic, triggered by the `find_events` (Tool Workflow) node.\n*   **Receives:** User event search criteria (`query`, `city`, `country`, `date-range`, `interests`).\n*   **Passes Data To:** The `event_finder_agent` (AI Agent) node."},"typeVersion":1},{"id":"3b2922cd-8fbb-4f1f-95e9-4a48dc07718a","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[20,720],"parameters":{"color":4,"width":740,"height":520,"content":"## 🧠 event_finder_agent (Core Logic)\n\n🤖 **The Brain of the Operation**\n*   **Purpose:** Processes the user's request to find events using available tools and LLM reasoning.\n*   **Model:** `models/gemini-2.5-flash-preview-05-20` (via `Google Gemini Chat Model` node).\n*   **System Prompt:** Defined in this node. Guides the AI on its persona, how to use tools, desired output format, and search strategy (see its System Message parameter).\n*   **Tools Used:**\n    *   `brave_web_search` (MCP Client)\n    *   `brave_local_search` (MCP Client)\n    *   `google_gemini_event_search` (Gemini Search Tool)\n    *   `jina_ai_web_page_scraper` (Jina AI Tool)\n*   **Memory Setup:** Uses `Simple Memory` (Window Buffer Memory) to retain short-term conversation context.\n*   **Input:** Event search criteria from `even_finder_workflow`.\n*   **Output:** Formatted markdown string containing event details, or a message if no events are found. This output becomes the result of the `find_events` tool call."},"typeVersion":1},{"id":"dbf29f77-6557-42aa-831b-3ad5590bb301","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[260,1660],"parameters":{"color":6,"width":620,"height":300,"content":"## 💾 Agent Memory (Simple Memory)\n\n🧠 **Short-Term Recall**\n*   **Purpose:** Provides conversation memory to the `event_finder_agent`.\n*   **Type:** Window Buffer Memory (keeps a limited history of interactions).\n*   **Session Key:** `={{ $execution.id }}` (Ensures memory is unique to each execution run of this agent logic).\n*   **Importance:** Allows the agent to potentially remember previous turns *if this workflow were part of a longer chat*, though for a single tool call, its main role is to fulfill the agent's memory requirement."},"typeVersion":1},{"id":"5d5143db-87d2-449c-9460-32f7d465410b","name":"Sticky Note9","type":"n8n-nodes-base.stickyNote","position":[960,720],"parameters":{"color":5,"width":460,"height":620,"content":"## 🛠️ Tool: brave_web_search (MCP Client)\n\n🌐 **Broad Web Searching**\n*   **Connection:** Uses `smithery brave search` credential.\n*   **Purpose of External Tool:** Performs general web searches via Brave Search API (exposed through Smithery MCP).\n*   **AI Interaction:** Agent uses this for broad event queries, finding event listing sites, or general info.\n    *   Example AI-generated params: `{\"query\": \"music festivals Australia July 2025\"}`\n*   **Output:** Search results (list of URLs, snippets)."},"typeVersion":1},{"id":"d943edef-7382-4b1b-b848-c923c99cc72b","name":"Sticky Note10","type":"n8n-nodes-base.stickyNote","position":[1540,720],"parameters":{"color":5,"width":460,"height":620,"content":"## 🛠️ Tool: brave_local_search (MCP Client)\n\n📍 **Local Area Searching**\n*   **Connection:** Uses `smithery brave search` credential.\n*   **Purpose of External Tool:** Finds local events/venues using Brave Local Search API (via Smithery MCP).\n*   **AI Interaction:** Agent prioritizes this for city-specific queries.\n    *   Example AI-generated params: `{\"query\": \"artisan markets Perth WA\"}`\n*   **Output:** Local search results."},"typeVersion":1},{"id":"bde5341b-3a99-48c9-a43d-9ebcc5172f14","name":"Sticky Note11","type":"n8n-nodes-base.stickyNote","position":[2120,720],"parameters":{"color":5,"width":460,"height":620,"content":"## 🛠️ Tool: google_gemini_event_search (Gemini Search Tool)\n\n✨ **Advanced Event Searching**\n*   **Connection:** Uses `Gemini Credentials account` credential.\n*   **Purpose of External Tool:** Leverages Google Gemini's advanced search capabilities for more nuanced or complex event queries.\n*   **AI Interaction:** Agent uses this for multi-faceted queries or when other searches are insufficient.\n    *   Example AI-generated params: `{\"query\": \"outdoor family events with craft workshops Perth July 2025\"}`\n*   **Output:** Rich search results, potentially with structured data."},"typeVersion":1},{"id":"a7c340dd-efac-415c-a922-f3ef457cb072","name":"Sticky Note12","type":"n8n-nodes-base.stickyNote","position":[2700,720],"parameters":{"color":5,"width":460,"height":620,"content":"## 🛠️ Tool: jina_ai_web_page_scraper (Jina AI Tool)\n\n📄 **Detailed Content Extraction**\n*   **Connection:** Uses `Jina AI account` credential.\n*   **Purpose of External Tool:** Scrapes and summarizes content from specific event URLs found by search tools.\n*   **AI Interaction:** Agent uses this to get detailed descriptions, dates, and locations from event pages.\n    *   Example AI-generated params: `{\"url\": \"https://example-event.com/details\"}`\n*   **Output:** Markdown content of the scraped page. **CRITICAL:** Use sparingly due to timeout limits."},"typeVersion":1},{"id":"2f1944ad-f803-4712-94a1-5ec902e7def4","name":"Sticky Note13","type":"n8n-nodes-base.stickyNote","position":[1680,-900],"parameters":{"color":2,"width":740,"height":360,"content":"## 💡 n8n AI Agent as an MCP Service (This Workflow's Pattern)\n\n**This workflow demonstrates a self-contained n8n AI Agent exposed as an MCP Service.**\n*   **What this \"Agent Logic\" part does:** Implements the core intelligence for finding local events. It receives a task (event criteria), uses its LLM (`Google Gemini Chat Model`) and a suite of tools (`brave_web_search`, `brave_local_search`, `google_gemini_event_search`, `jina_ai_web_page_scraper`) to gather information, and then formats a response.\n*   **How it works internally:** The `event_finder_agent` node orchestrates tool calls based on its system prompt and the user's request. Memory helps maintain context for the LLM.\n*   **Why this pattern is useful:**\n    1.  **Encapsulation:** Complex logic is bundled into a reusable agent.\n    2.  **Accessibility:** The MCP Server part makes this agent callable by other systems as a simple tool.\n    3.  **Single File Simplicity:** For moderately complex agents, keeping the MCP server and agent logic in one file can simplify deployment and management."},"typeVersion":1},{"id":"934c840a-f8b6-416a-a5a8-68b724f27687","name":"Sticky Note14","type":"n8n-nodes-base.stickyNote","position":[1680,-500],"parameters":{"color":2,"width":740,"height":440,"content":"## 🔑 External Service Credentials (Agent Logic Area)\n\nList of credentials used by tools within this agent logic:\n\n1.  **Tool Nodes:** `brave_web_search`, `brave_local_search`\n    *   **n8n Credential Name:** `smithery brave search`\n    *   **Target Service (Example):** Smithery MCP for Brave Search\n2.  **Tool Node:** `Google Gemini Chat Model` (LLM)\n    *   **n8n Credential Name:** `Google Gemini Context7`\n    *   **Target Service:** Google AI (Generative Language API)\n3.  **Tool Node:** `google_gemini_event_search`\n    *   **n8n Credential Name:** `Gemini Credentials account`\n    *   **Target Service:** Google AI (Gemini Search API / Vertex AI Search)\n4.  **Tool Node:** `jina_ai_web_page_scraper`\n    *   **n8n Credential Name:** `Jina AI account`\n    *   **Target Service:** Jina AI API"},"typeVersion":1},{"id":"96746f76-936e-467b-94f7-7b2fe32728a9","name":"Sticky Note15","type":"n8n-nodes-base.stickyNote","position":[-720,1600],"parameters":{"color":6,"width":740,"height":220,"content":"## ⚙️ Key LLM & Agent Settings (Agent Logic Area)\n\n*   **LLM Model:** `models/gemini-2.5-flash-preview-05-20` (in `Google Gemini Chat Model` node)\n*   **System Prompt Location:** Within the `event_finder_agent` node, \"System Message\" parameter.\n*   **Memory Type/Key:** Window Buffer Memory (`Simple Memory` node), Session Key: `={{ $execution.id }}`"},"typeVersion":1},{"id":"338692d0-096a-42b8-a7bc-4ee897b251a2","name":"Sticky Note16","type":"n8n-nodes-base.stickyNote","position":[2480,-900],"parameters":{"color":2,"width":740,"height":360,"content":"## 🎯 Sub-Workflow: Local Event Finder Core Logic (Agent Logic Area)\n\n*   **Purpose:** This section of the workflow is dedicated to understanding the user's event request, utilizing search and scraping tools effectively, and synthesizing the findings into a helpful, formatted response.\n*   **Expected Input Details (from `even_finder_workflow`):**\n    *   `query`: (string) e.g., \"mountain biking and beer events\"\n    *   `city`: (string) e.g., \"Perth\"\n    *   `country`: (string) e.g., \"Australia\"\n    *   `date-range`: (string) e.g., \"July 2025\"\n    *   `interests`: (string) e.g., \"mountain biking, craft beer\""},"typeVersion":1},{"id":"7e276d1e-6746-4133-8dcd-cf886c0d3199","name":"Sticky Note17","type":"n8n-nodes-base.stickyNote","position":[2480,-500],"parameters":{"color":2,"width":740,"height":360,"content":"## 🛠️ Troubleshooting Tips (Agent Logic Area)\n\n*   **Check Agent Logs:** Examine the execution logs of the `event_finder_agent` node for tool call details, LLM interactions, and errors.\n*   **Test MCP Client Tools Individually:** If a tool seems to fail (e.g., `brave_web_search`), test its node with fixed inputs to isolate issues.\n*   **Test External Services:** Ensure the underlying services (Brave Search via Smithery, Google AI, Jina AI) are operational.\n*   **Verify Credentials:** Double-check all credential configurations (`smithery brave search`, `Google Gemini Context7`, `Gemini Credentials account`, `Jina AI account`).\n*   **Review System Prompt:** Ensure the system prompt in `event_finder_agent` clearly instructs the AI and aligns with tool capabilities.\n*   **Inspect `jina_ai_web_page_scraper` Usage:** This tool is time-sensitive. Ensure it's not trying to scrape too many pages or very large/slow pages, which could lead to timeouts."},"typeVersion":1}],"active":true,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"9598b47f-389a-4d1c-b46e-f87a066b416e","connections":{"find_events":{"ai_tool":[[{"node":"local_event_finder","type":"ai_tool","index":0}]]},"Simple Memory":{"ai_memory":[[{"node":"event_finder_agent","type":"ai_memory","index":0}]]},"brave_web_search":{"ai_tool":[[{"node":"event_finder_agent","type":"ai_tool","index":0}]]},"brave_local_search":{"ai_tool":[[{"node":"event_finder_agent","type":"ai_tool","index":0}]]},"even_finder_workflow":{"main":[[{"node":"event_finder_agent","type":"main","index":0}]]},"Google Gemini Chat Model":{"ai_languageModel":[[{"node":"event_finder_agent","type":"ai_languageModel","index":0}]]},"jina_ai_web_page_scraper":{"ai_tool":[[{"node":"event_finder_agent","type":"ai_tool","index":0}]]},"google_gemini_event_search":{"ai_tool":[[{"node":"event_finder_agent","type":"ai_tool","index":0}]]}}}


name: Compose/Stitch Separate Images together using n8n & Gemini AI Image Editing
author_name: Jimleuk
author_username: jimleuk
nodes_used: ["n8n-nodes-base.httpRequest","n8n-nodes-base.googleDrive"]
categories: []
created_at: 2025-06-09T13:00:49.415Z
updated_at: 2025-06-09T13:00:49.415Z
url: https://n8n.io/workflows/4817
scraped_at: 2025-06-19 22:49:05
description:
  This n8n template demonstrates how to use AI to compose or "stitch" separate images together to generate a new image which retains the source assets and consistent style.

  Use cases are many: Try producing storyboard scenes with consistent characters, marketing material with existing product assets or trying on different articles on fashion!

  Good to know
  At time of writing, each image generated will cost $0.039 USD. See Gemini Pricing for updated info.
  The model used in this workflow is geo-restricted! If it says model not found, it may not be available in your country or region.

  How it works
  We'll import our required assets via our Cloud storage using the HTTP node.
  The images are then converted to base64 strings and aggregated so we can use it for our AI model.
  Gemini's image generation model is used which takes all 3 images and a prompt that we define. Our prompt instructs the model on how to compose the final image.
  Gemini generates a new image but uses the original 3 assets to do so. The consistency to the source images is very high and shows little signs of hallucinations!
  Gemini's output is base64 so we use a "Convert to file" node to convert the data to binary.
  The final binary image is then uploaded to Google Drive to complete the demonstration.

  How to use
  The manual trigger node is used as an example but feel free to replace this with other triggers such as webhook or even a form.
  Technically, you should be able to compose even more images but of course, the generation will take longer and cost more.

  Requirements
  Gemini account for LLM and Image generation
  Google drive for upload

  Customising this workflow
  AI Image editing can be used for many use-cases. Try a popular use-case such as virtual try-on for fashion or applying branding on editing image assets.

workflow_json:
  {"meta":{"instanceId":"408f9fb9940c3cb18ffdef0e0150fe342d6e655c3a9fac21f0f644e8bedabcd9"},"nodes":[{"id":"bd94ff7b-0f66-45f7-bbab-bb2be0406532","name":"When clicking ‘Execute workflow’","type":"n8n-nodes-base.manualTrigger","position":[-540,320],"parameters":{},"typeVersion":1},{"id":"fdd66c07-8168-4f94-8ff5-ba4ceed476a9","name":"Get Image Contents","type":"n8n-nodes-base.set","position":[1400,320],"parameters":{"options":{},"assignments":{"assignments":[{"id":"021aad70-de11-4387-844e-7e7dfd3b1044","name":"image","type":"string","value":"={{ $json.candidates[0].content.parts.find(part => part.inlineData).inlineData.data }}"},{"id":"62877ef7-2057-4d35-a44b-1d58fa1f1769","name":"mimeType","type":"string","value":"={{ $json.candidates[0].content.parts.find(part => part.inlineData).inlineData.mimeType }}"}]}},"typeVersion":3.4},{"id":"e23db650-d0fa-4d87-87ea-3ab2e78292d8","name":"Upload to Drive","type":"n8n-nodes-base.googleDrive","position":[2020,320],"parameters":{"name":"=file_restored_{{ $itemIndex }}.{{ $binary.data.fileExtension }}","driveId":{"__rl":true,"mode":"list","value":"My Drive"},"options":{},"folderId":{"__rl":true,"mode":"list","value":"root","cachedResultName":"/ (Root folder)"}},"credentials":{"googleDriveOAuth2Api":{"id":"yOwz41gMQclOadgu","name":"Google Drive account"}},"typeVersion":3},{"id":"0a8bd3f0-a6e9-4862-942c-20ce336ab24e","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[1020,60],"parameters":{"color":7,"width":640,"height":460,"content":"## 2. Use Gemini LLM to Compose Images Together\n[Read more about Gemini's Text and Image to Image Editing](https://ai.google.dev/gemini-api/docs/image-generation#gemini-image-editing)\n\nComposing or \"Stitching\" images together may not seem particularly exciting but with Text-and-image-to-image capability, we can instruct the AI on \"how\" to put the images together. This is incredibly powerful feature when you need to use existing imagery or graphics in new pieces of work."},"typeVersion":1},{"id":"8a87bcea-7b60-46d8-9070-380397d9d0d8","name":"Convert to File","type":"n8n-nodes-base.convertToFile","onError":"continueRegularOutput","position":[1820,320],"parameters":{"options":{"mimeType":"={{ $json.mimeType }}"},"operation":"toBinary","sourceProperty":"image"},"typeVersion":1.1},{"id":"0ea0a3bf-e4fb-4beb-8a02-405602e17558","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1700,60],"parameters":{"color":7,"width":560,"height":460,"content":"## 3. Upload to Google Drive\n[Read more about Google Drive node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.googledrive)\n\nGemini outputs the image data as a base64 string so conversion to binary is sometimes necessary such as when uploading to Google Drive. We're using Google drive here but you can upload to any destination of your choosing."},"typeVersion":1},{"id":"f6f9410f-f3ef-4b7b-88fe-774c30fe4e29","name":"Extract from File","type":"n8n-nodes-base.extractFromFile","position":[600,320],"parameters":{"options":{},"operation":"binaryToPropery"},"typeVersion":1},{"id":"c41e5653-bd37-4b17-9226-e9edf3d58899","name":"Merge1","type":"n8n-nodes-base.merge","position":[380,320],"parameters":{"numberInputs":3},"typeVersion":3.2},{"id":"0fe5cc27-e378-4a62-8477-1b666c4dcbe6","name":"Aggregate1","type":"n8n-nodes-base.aggregate","position":[820,320],"parameters":{"options":{},"aggregate":"aggregateAllItemData"},"typeVersion":1},{"id":"cd489b5f-0447-4d3e-84d1-a22142d02708","name":"Character","type":"n8n-nodes-base.httpRequest","position":[-300,120],"parameters":{"url":"https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/qwitjyhejockuxfvkk5g","options":{}},"typeVersion":4.2},{"id":"74e05106-26c0-4d59-adf9-274f2a1ddd7b","name":"Dalmation","type":"n8n-nodes-base.httpRequest","position":[-180,320],"parameters":{"url":"https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/gxcc0xnghpbthwt8fpec","options":{}},"typeVersion":4.2},{"id":"2bd84982-3984-4c22-a3de-0c871f5bc2ea","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[2300,60],"parameters":{"width":480,"height":540,"content":"## Final Output\n![](https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/rrezma7shzwffosy5apn#full-width)"},"typeVersion":1},{"id":"4e3155bf-983b-46b4-b6cb-38278edc34fb","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-300,-180],"parameters":{"width":220,"height":280,"content":"## Character\n![](https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/qwitjyhejockuxfvkk5g#full-width)"},"typeVersion":1},{"id":"01486147-0ddf-4055-9ebf-5bc6a884852c","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-40,120],"parameters":{"height":300,"content":"## Dalmation\n![](https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/gxcc0xnghpbthwt8fpec#full-width)"},"typeVersion":1},{"id":"e2153852-33b3-41dc-adcf-122027ada5a6","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-180,520],"parameters":{"height":300,"content":"## Sofa\n![](https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/nyghscauxtcfl4dve6of#full-width)"},"typeVersion":1},{"id":"510619c4-1e9c-4466-95f1-5eaa72d6ecc5","name":"Sofa","type":"n8n-nodes-base.httpRequest","position":[100,520],"parameters":{"url":"https://res.cloudinary.com/daglih2g8/image/upload/f_auto,q_auto/v1/n8n-workflows/nyghscauxtcfl4dve6of","options":{}},"typeVersion":4.2},{"id":"522cdb05-558c-4bd4-a4af-1a400bc641f9","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[300,60],"parameters":{"color":7,"width":680,"height":460,"content":"## 1. Convert Separate Images to Base64 Strings\n[Read more about the Extract from File node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.extractfromfile)\n\nTo use our images in this workflow, we will need to convert the binary data to base64 strings. This is later passed to the Gemini API to work on."},"typeVersion":1},{"id":"ce28bdf0-a03e-486c-9dd4-2aeb0896519e","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[-1080,-220],"parameters":{"width":460,"height":960,"content":"## Try It Out!\n### This n8n template demonstrates how to use AI to compose or \"stitch\" separate images together to generate a new image which retains the source assets and consistent style.\n\nUse cases are many: Try producing storyboard scenes with consistent characters, marketing material with existing product assets or trying on different articles on fashion!\n\n### How it works\n* We'll import our required assets via our Cloud storage using the HTTP node.\n* The images are then converted to base64 strings and aggregated so we can use it for our AI model.\n* Gemini's image generation model is used which takes all 3 images and a prompt that we define. Our prompt instructs the model on how to compose the final image.\n* Gemini generates a new image but uses the original 3 assets to do so. The consistency to the source images is very high and shows little signs of hallucinations!\n* Gemini's output is base64 so we use a \"Convert to file\" node to convert the data to binary.\n* The final binary image is then uploaded to Google Drive to complete the demonstration.\n\n### How to use\n* The manual trigger node is used as an example but feel free to replace this with other triggers such as webhook or even a form.\n* Technically, you should be able to compose even more images but of course, the generation will take longer and cost more.\n\n### Requirements\n* Gemini account for LLM and Image generation\n* Google drive for upload\n\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":"086cae2e-3b21-4262-917d-9d9f261d20d6","name":"Gemini Image Compose","type":"n8n-nodes-base.httpRequest","position":[1180,320],"parameters":{"url":"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-preview-image-generation:generateContent","method":"POST","options":{},"jsonBody":"={\n  \"contents\": [\n    {\n      \"parts\": [\n        {\n          \"text\": \"The character is sitting on the sofa, and the dalmation is lying on the blanket sleeping on the floor. Retain the image style of the character image.\"\n        },\n        {\n          \"inline_data\": {\n            \"mime_type\": \"image/png\",\n            \"data\": \"{{ $json.data[0].data }}\"\n          }\n        },\n        {\n          \"inline_data\": {\n            \"mime_type\": \"image/png\",\n            \"data\": \"{{ $json.data[1].data }}\"\n          }\n        },\n        {\n          \"inline_data\": {\n            \"mime_type\": \"image/png\",\n            \"data\": \"{{ $json.data[2].data }}\"\n          }\n        }\n      ]\n    }\n  ],\n  \"generationConfig\": {\n    \"responseModalities\": [\n      \"TEXT\",\n      \"IMAGE\"\n    ]\n  }\n}","sendBody":true,"specifyBody":"json","authentication":"predefinedCredentialType","nodeCredentialType":"googlePalmApi"},"credentials":{"googlePalmApi":{"id":"dSxo6ns5wn658r8N","name":"Google Gemini(PaLM) Api account"}},"typeVersion":4.2},{"id":"48127e5f-441a-4c46-9c96-3953e26ae092","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[-1080,760],"parameters":{"color":5,"width":460,"height":140,"content":"### Geo Restrictions!\nPlease note at time of writing, the Gemini Image Generation model is restricted to certain countries and regions. If you're getting model not found errors, it's possible the model may not be available in your country!"},"typeVersion":1}],"pinData":{},"connections":{"Sofa":{"main":[[{"node":"Merge1","type":"main","index":2}]]},"Merge1":{"main":[[{"node":"Extract from File","type":"main","index":0}]]},"Character":{"main":[[{"node":"Merge1","type":"main","index":0}]]},"Dalmation":{"main":[[{"node":"Merge1","type":"main","index":1}]]},"Aggregate1":{"main":[[{"node":"Gemini Image Compose","type":"main","index":0}]]},"Convert to File":{"main":[[{"node":"Upload to Drive","type":"main","index":0}]]},"Extract from File":{"main":[[{"node":"Aggregate1","type":"main","index":0}]]},"Get Image Contents":{"main":[[{"node":"Convert to File","type":"main","index":0}]]},"Gemini Image Compose":{"main":[[{"node":"Get Image Contents","type":"main","index":0}]]},"When clicking ‘Execute workflow’":{"main":[[{"node":"Dalmation","type":"main","index":0},{"node":"Sofa","type":"main","index":0},{"node":"Character","type":"main","index":0}]]}}}


name: Send Telegram Notification for New WooCommerce Orders
author_name: Mohammadreza azari
author_username: mrazari
nodes_used: ["n8n-nodes-base.telegram"]
categories: []
created_at: 2025-06-09T14:03:41.338Z
updated_at: 2025-06-09T14:03:41.338Z
url: https://n8n.io/workflows/4818
scraped_at: 2025-06-19 22:49:35
description:
  🔧 How it works:
  • The workflow triggers when a new order is created in WooCommerce.
  • It extracts order details including ID, status, total, and products list.
  • Sends a formatted message via Telegram to the store admin.
  • Includes a clickable button that links directly to the order view page.

  ⚙️ Set up steps:
  • Estimated setup time: 5–10 minutes.
  • Requires active WooCommerce REST API credentials.
  • Requires a Telegram bot and your admin chat ID.
  • Replace the Telegram chatId and WooCommerce credentials in the workflow.
  • Make sure your WooCommerce site allows external API access.

workflow_json:
  {"meta":{"instanceId":"370f0437fbf8d71caf7e9230e115239afcf5012c55ac368aa9dee29869df4a6b","templateCredsSetupCompleted":true},"nodes":[{"id":"31722179-ef48-4a85-9a0c-ffc824e59493","name":"WooCommerce Trigger","type":"n8n-nodes-base.wooCommerceTrigger","position":[-120,-20],"webhookId":"6fc419e7-2af4-44e0-af83-b4f0a408138b","parameters":{"event":"order.created"},"credentials":{"wooCommerceApi":{"id":"7FzoXyPl8TAUChEg","name":"WooCommerce account"}},"typeVersion":1},{"id":"6564d1a2-87b0-4ffb-bc60-54256a85058f","name":"Telegram","type":"n8n-nodes-base.telegram","position":[100,-20],"webhookId":"7ff0563d-eb68-4e68-a32a-54bdeab7c7ed","parameters":{"text":"=🛒 New Order Received!\n\n🆔 Order #: {{$json.id}}  \n💰 Total: {{$json.total}} USD  \n📅 Date: {{$json.date_created}}  \n🔖 Status: {{$json.status}}  \n\n🛍️ Products:\n{{ $json.line_items.map(item => `- ${item.name} × ${item.quantity} = ${item.total} USD`).join('\\n') }}\n\n👁️‍🗨️ Click the button below to view this order.","chatId":"8025476048","replyMarkup":"inlineKeyboard","inlineKeyboard":{"rows":[{"row":{"buttons":[{"text":"🔗 View Order","additionalFields":{"web_app":{"url":"={{ $json.payment_url }}"}}}]}}]},"additionalFields":{}},"credentials":{"telegramApi":{"id":"QCMzalgAAwQJ4qi4","name":"n8nlearncombot"}},"typeVersion":1.2},{"id":"b5e0a35b-f794-4f0a-b76e-f63ac8eddc7b","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-880,-360],"parameters":{"width":680,"height":560,"content":"## 🛠 Setup Instructions\n\n### 🔧 Configuration Steps\n- **Replace** the `chatId` field in the Telegram node with your own Telegram **user ID** or **group ID**.\n- **Make sure** your Telegram bot is added to the group/channel if you're using one.\n- **Update** the WooCommerce API credentials with your **Consumer Key**, **Secret**, and **Base URL**.\n- **Ensure** your WooCommerce site allows external REST API access.\n- The order button uses `{{$json.payment_url}}`, so you **don’t need to hardcode your domain**.\n\n### 💵 Currency\n- The total amount and product prices are shown in **USD** for international compatibility.\n- You can change it to another currency if needed.\n\n---\n\n### ✅ What This Workflow Does\n- Triggers when a **new order** is placed in WooCommerce.\n- Sends a **Telegram message** to the admin.\n- Includes:\n  - Order ID, date, status, and total\n  - List of products\n  - **Button** to view the order in WooCommerce\n\n---\n"},"typeVersion":1}],"pinData":{},"connections":{"WooCommerce Trigger":{"main":[[{"node":"Telegram","type":"main","index":0}]]}}}


name: Search Google, Bing, Yandex & Extract Structured Results with Bright Data MCP & Google Gemini
author_name: Ranjan Dailata
author_username: ranjancse
categories: []
created_at: 2025-06-09T14:16:39.530Z
updated_at: 2025-06-09T14:16:39.530Z
url: https://n8n.io/workflows/4820
scraped_at: 2025-06-19 22:50:03
description:
  Notice
  Community nodes can only be installed on self-hosted instances of n8n.

  Who this is for?

  The Search Engine Intelligence Extractor is a powerful n8n automation that leverages Bright Data’s MCP based AI Agents to simulate human-like searches across Google, Bing, and Yandex, and then distills clean, structured insights using Google Gemini.

  This workflow is tailored for:

  SEO analysts researching competitors or market trends

  Market researchers needing real-time search visibility

  Journalists & content writers gathering contextual insights

  AI developers creating intelligent assistants

  Digital marketers tracking brand mentions or news

  What problem is this workflow solving?

  Traditional scraping of search engines is often blocked, cluttered, or filled with irrelevant information. Manually analyzing and cleaning this data for insight is time-consuming.

  This workflow solves the problem by:

  Simulating real user search behavior via Bright Data MCP based AI Agent

  Performing multi-platform search (Google, Bing, Yandex) in one unified flow

  Extracting clean, human-readable results (stripping ads, navigation, etc.)

  Structuring the content using Google Gemini LLM

  Automating delivery via Webhook or saving to disk

  What this workflow does

  Input Fields Node:

  Accepts the search query

  Accepts action for example - Perform a google search. Replace the action with bing, yandex etc. for other search providers

  Accepts Webhook notification URL

  Bright Data MCP Agent Execution:

  Triggers Bright Data’s intelligent search agent

  Handles search navigation, result loading, pagination

  Human Readable Data Extractor:

  Cleanses HTML, removes ads, footers, irrelevant links

  Produces a readable narrative of results

  Final Output Handling:

  Saves the processed response to disk

  Sends the structured data to a Webhook for real-time use

  Pre-conditions

  Knowledge of Model Context Protocol (MCP) is highly essential. Please read this blog post - model-context-protocol
  You need to have the Bright Data account and do the necessary setup as mentioned in the Setup section below.
  You need to have the Google Gemini API Key. Visit Google AI Studio
  You need to install the Bright Data MCP Server @brightdata/mcp
  You need to install the n8n-nodes-mcp

  Setup
  Please make sure to setup n8n locally with MCP Servers by navigating to n8n-nodes-mcp
  Please make sure to install the Bright Data MCP Server @brightdata/mcp  on your local machine.
  Sign up at Bright Data.
  Create a Web Unlocker proxy zone called mcp_unlocker on Bright Data control panel.
  Navigate to Proxies & Scraping and create a new Web Unlocker zone by selecting Web Unlocker API under Scraping Solutions.
  In n8n, configure the Google Gemini(PaLM) Api account with the Google Gemini API key (or access through Vertex AI or proxy).
  In n8n, configure the credentials to connect with MCP Client (STDIO) account with the Bright Data MCP Server as shown below.



  Make sure to copy the Bright Data API_TOKEN within the Environments textbox above as API_TOKEN=&lt;your-token&gt;

  How to customize this workflow to your needs

  Add Scheduled Execution
  Add a Cron trigger to run this workflow on a set schedule (e.g., daily/weekly keyword tracking).

  Push Results to Custom Destinations

  Connect output to:

  Google Sheets (for analytics or dashboards)

  PostgreSQL or MySQL DBs (for structured storage)

  Notion or Airtable (for content pipelines)

  Slack or Email (for alerting teams)


  Customize Webhook Notifications
  Update the Webhook URL in the notification node to push processed results to external APIs, CRMs, or real-time dashboards.

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

workflow_json:
  {"id":"XSN9T4R0IyqcV2gC","meta":{"instanceId":"885b4fb4a6a9c2cb5621429a7b972df0d05bb724c20ac7dac7171b62f1c7ef40","templateCredsSetupCompleted":true},"name":"Perform Google, Bing, Yandex Search with Bright Data MCP Agent & Google Gemini","tags":[{"id":"Kujft2FOjmOVQAmJ","name":"Engineering","createdAt":"2025-04-09T01:31:00.558Z","updatedAt":"2025-04-09T01:31:00.558Z"},{"id":"ZOwtAMLepQaGW76t","name":"Building Blocks","createdAt":"2025-04-13T15:23:40.462Z","updatedAt":"2025-04-13T15:23:40.462Z"},{"id":"ddPkw7Hg5dZhQu2w","name":"AI","createdAt":"2025-04-13T05:38:08.053Z","updatedAt":"2025-04-13T05:38:08.053Z"}],"nodes":[{"id":"80b9e843-974a-4a93-871f-3ead444d1757","name":"When clicking ‘Test workflow’","type":"n8n-nodes-base.manualTrigger","position":[-1300,300],"parameters":{},"typeVersion":1},{"id":"2debe6c6-80ef-4fba-a40d-fcfd8a09eefa","name":"Bright Data MCP Client List Tools","type":"n8n-nodes-mcp.mcpClient","position":[-1080,300],"parameters":{},"credentials":{"mcpClientApi":{"id":"JtatFSfA2kkwctYa","name":"MCP Client (STDIO) account"}},"typeVersion":1},{"id":"0b66f5bb-66bb-41cf-b165-552d5b169dce","name":"Create a binary data","type":"n8n-nodes-base.function","position":[180,220],"parameters":{"functionCode":"items[0].binary = {\n  data: {\n    data: new Buffer(JSON.stringify(items[0].json, null, 2)).toString('base64')\n  }\n};\nreturn items;"},"typeVersion":1},{"id":"8516c6d6-fcae-42ab-8921-9f1d5500f73b","name":"MCP Client for Google Search","type":"n8n-nodes-mcp.mcpClientTool","position":[-720,600],"parameters":{"toolName":"search_engine","operation":"executeTool","toolParameters":"={\n    \"query\": \"{{ $json.query }}\",\n    \"engine\": \"google\"\n} ","descriptionType":"manual","toolDescription":"Perform a Google Search and Scrape the Google Search Result"},"credentials":{"mcpClientApi":{"id":"JtatFSfA2kkwctYa","name":"MCP Client (STDIO) account"}},"typeVersion":1},{"id":"a17ff821-c508-4b61-8d35-e7f1580e5bb1","name":"Set the Input Fields","type":"n8n-nodes-base.set","position":[-860,300],"parameters":{"options":{},"assignments":{"assignments":[{"id":"219c5e66-e167-44c3-bc65-612c70e8d4a1","name":"query","type":"string","value":"Bright Data"},{"id":"2b9b0541-5c5e-446f-aeaf-8c9ce00dfa00","name":"action","type":"string","value":"Perform Bing search"},{"id":"bcc3ce2a-3708-4b6f-8ddd-3b5e611c63d0","name":"webhook_notification_url","type":"string","value":"https://webhook.site/c9118da2-1c54-460f-a83a-e5131b7098db"}]}},"typeVersion":3.4},{"id":"42639030-338c-4d30-a2e0-a5aaa9325191","name":"MCP Client for Bing Search","type":"n8n-nodes-mcp.mcpClientTool","position":[-500,600],"parameters":{"toolName":"search_engine","operation":"executeTool","toolParameters":"{\n    \"query\": \"{{ $json.query }}\",\n    \"engine\": \"bing\"\n} ","descriptionType":"manual","toolDescription":"Perform a Bing Search and Scrape the Bing Search Result"},"credentials":{"mcpClientApi":{"id":"JtatFSfA2kkwctYa","name":"MCP Client (STDIO) account"}},"typeVersion":1},{"id":"18f1374e-2516-481c-9fed-3c8757a21296","name":"MCP Client for Yandex Search","type":"n8n-nodes-mcp.mcpClientTool","position":[-300,600],"parameters":{"toolName":"search_engine","operation":"executeTool","toolParameters":"{\n    \"query\": \"{{ $json.query }}\",\n    \"engine\": \"yandex\"\n} ","descriptionType":"manual","toolDescription":"Perform a Yandex Search and Scrape the Yandex Search Result"},"credentials":{"mcpClientApi":{"id":"JtatFSfA2kkwctYa","name":"MCP Client (STDIO) account"}},"typeVersion":1},{"id":"ff15f988-5f23-4a22-b2fb-25bdd558fce4","name":"Bright Data Search AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[-600,300],"parameters":{"text":"={{ $json.action }}\n\nMake sure to output the response as returned by th specific tool.","options":{},"promptType":"define","hasOutputParser":true},"typeVersion":2},{"id":"cd255a57-2260-4781-a9b1-e38a4d224572","name":"Google Gemini Chat Model for Search Agent","type":"@n8n/n8n-nodes-langchain.lmChatGoogleGemini","position":[-900,600],"parameters":{"options":{},"modelName":"models/gemini-2.0-flash-exp"},"credentials":{"googlePalmApi":{"id":"YeO7dHZnuGBVQKVZ","name":"Google Gemini(PaLM) Api account"}},"typeVersion":1},{"id":"51db57ef-8626-4268-b377-cd95021537c8","name":"Write the search result to disk","type":"n8n-nodes-base.readWriteFile","position":[420,220],"parameters":{"options":{},"fileName":"d:\\Scraped-Search-Results.json","operation":"write"},"typeVersion":1},{"id":"afa11162-6e5f-48ee-81a9-120eebf79a72","name":"Webhook for clean data extractor","type":"n8n-nodes-base.httpRequest","position":[180,420],"parameters":{"url":"={{ $('Set the Input Fields').item.json.webhook_notification_url }}","options":{},"sendBody":true,"bodyParameters":{"parameters":[{"name":"response","value":"={{ $json.output.search_response }}"}]}},"typeVersion":4.2},{"id":"07ea15dc-d54f-424c-bb75-27054be6996d","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-400,140],"parameters":{"color":3,"width":440,"height":120,"content":"## Disclaimer\nThis template is only available on n8n self-hosted as it's making use of the community node for MCP Client."},"typeVersion":1},{"id":"8ed88da4-cfd8-4c27-a737-1c718143e1a4","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-860,20],"parameters":{"color":5,"width":440,"height":240,"content":"## LLM Usages\n\nGoogle Gemini LLM is being utilized for the structured data extraction handling."},"typeVersion":1},{"id":"b533b59c-5007-4f87-a862-f2765be3d27b","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-1320,-420],"parameters":{"color":7,"width":440,"height":360,"content":"## Logo\n\n\n![logo](https://images.seeklogo.com/logo-png/43/1/brightdata-logo-png_seeklogo-439974.png)\n"},"typeVersion":1},{"id":"17265f2a-5224-498c-bf50-36b87a1c3b22","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[-1320,-40],"parameters":{"width":440,"height":300,"content":"## Note\n\nDeals with the Google, Bing, Yandex Search by leveraging the Bright Data MCP Client.\n\n**Please make sure to set the input fields with query, action, Webhook notification URL. Test using https://webhook.site/**\n\nAction - \n1. Perform Google search\n2. Perform Bing search\n3. Perform Yandex search"},"typeVersion":1},{"id":"902a8d8e-d4ad-4934-8c4d-10c7b66aac3c","name":"Human Readable Data Extractor","type":"@n8n/n8n-nodes-langchain.informationExtractor","position":[-240,300],"parameters":{"text":"=You are a helpful AI assistant. Given the following search result, return a clean, human-readable information.\n\nRemove any HTML tags, Ignore irrelevant links, ads, navigation text, or footers.\n\nHere's the content -  {{ $json.output }}\n\nImportant - Do not output your own thoughts or suggestions.","options":{},"attributes":{"attributes":[{"name":"search_response","description":"Search Response"}]}},"typeVersion":1.1},{"id":"1eca092e-da55-4025-85d1-d1d715e23f83","name":"Google Gemini Chat Model for Human Readable Data Extractor","type":"@n8n/n8n-nodes-langchain.lmChatGoogleGemini","position":[-120,500],"parameters":{"options":{},"modelName":"models/gemini-2.0-flash-exp"},"credentials":{"googlePalmApi":{"id":"YeO7dHZnuGBVQKVZ","name":"Google Gemini(PaLM) Api account"}},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"0cb1ae5e-f384-48ec-aaa8-e11362a32527","connections":{"Create a binary data":{"main":[[{"node":"Write the search result to disk","type":"main","index":0}]]},"Set the Input Fields":{"main":[[{"node":"Bright Data Search AI Agent","type":"main","index":0}]]},"MCP Client for Bing Search":{"ai_tool":[[{"node":"Bright Data Search AI Agent","type":"ai_tool","index":0}]]},"Bright Data Search AI Agent":{"main":[[{"node":"Human Readable Data Extractor","type":"main","index":0}]]},"MCP Client for Google Search":{"ai_tool":[[{"node":"Bright Data Search AI Agent","type":"ai_tool","index":0}]]},"MCP Client for Yandex Search":{"ai_tool":[[{"node":"Bright Data Search AI Agent","type":"ai_tool","index":0}]]},"Human Readable Data Extractor":{"main":[[{"node":"Create a binary data","type":"main","index":0},{"node":"Webhook for clean data extractor","type":"main","index":0}]]},"Bright Data MCP Client List Tools":{"main":[[{"node":"Set the Input Fields","type":"main","index":0}]]},"When clicking ‘Test workflow’":{"main":[[{"node":"Bright Data MCP Client List Tools","type":"main","index":0}]]},"Google Gemini Chat Model for Search Agent":{"ai_languageModel":[[{"node":"Bright Data Search AI Agent","type":"ai_languageModel","index":0}]]},"Google Gemini Chat Model for Human Readable Data Extractor":{"ai_languageModel":[[{"node":"Human Readable Data Extractor","type":"ai_languageModel","index":0}]]}}}


name: Automated Lead Generation & Qualification with Google Maps, GPT-4 & HubSpot
author_name: David Olusola
author_username: dae221
categories: []
created_at: 2025-06-09T18:03:36.531Z
updated_at: 2025-06-09T18:03:36.531Z
url: https://n8n.io/workflows/4824
scraped_at: 2025-06-19 22:49:11
description:
  This n8n workflow automates CVE tracking by retrieving vulnerability details from the NVD API 🛡️, organizing and updating the data in Google Sheets 📊, and optionally alerting teams via Slack or Email 📩💬.

  Who is this for?

  This workflow is ideal for:

  Security operations (SecOps) teams 🧑‍💻
  DevSecOps engineers 🛠️
  IT compliance officers 🧾
  Vulnerability management analysts 🕵️
  Sysadmins or cloud engineers in regulated industries 🏢

  What problem does this workflow solve?

  Manually checking for the latest CVE information is inefficient and error-prone. This automation:

  Monitors NVD for CVE entries based on product or keyword filters 🔍
  Tracks new vulnerabilities and changes to existing ones ⏱️
  Logs all CVE data in a structured Google Sheet for ongoing review and audit 🧾
  Can trigger alerts or actions for high-severity CVEs 🚨

  What this workflow does

  This workflow builds an automated CVE monitoring system that:

  Queries the NVD API for vulnerability data matching keywords (e.g. "Apache", "Log4j") 📡
  Extracts relevant fields: CVE ID, description, severity (CVSS scores), published/modified dates, and affected products 🗂️
  Saves or updates the information in Google Sheets 📑
  Optionally filters for critical severity (e.g., CVSS &gt; 8.0) and sends Slack alerts or emails 📬
  Supports historical tracking and change detection over time 🕒

  Includes a Google Sheets template for tracking:

  CVE IDs and metadata
  Severity levels and scores
  Product/component tags
  Resolution/patch status tracking

  Setup

  Prerequisites

  You'll need:

  An n8n instance (cloud or self-hosted) ☁️
  A Google account + Google Sheets API credentials 📑
  (Optional) Slack webhook URL or email setup for notifications 💬

  Step 1: Configure API Inputs

  Open the 🔧 Configuration node and provide:

  NVD API parameters (keyword filters, date ranges, etc.)
  Google Sheet ID and tab name for output
  Slack webhook URL (optional)

  Step 2: Set Filters & Preferences

  Define:

  Target keywords or CPE filters (e.g. “Cisco ASA”, “Windows 10”) 🧩
  CVSS threshold for high/critical alerts 🎚️
  Update frequency (manual trigger, scheduled cron, webhook, etc.) 🔁

  Step 3: Connect to Google Sheets

  Update Sheet node with your destination Sheet ID
  Ensure columns like CVE ID, Description, Severity, Last Updated exist

  Step 4: Enable Alerts (Optional)

  Set up Slack node with your webhook URL or connect SMTP/Email node
  Format alert message with key CVE data

  Step 5: Activate and Run

  Save and activate the workflow 🔛
  Run manually or schedule it to run periodically (e.g., every 6 hours) ⏱️

  Customization Tips

  Add deduplication logic to avoid reprocessing the same CVEs ♻️
  Use filters to monitor only critical CVEs or specific vendors/vendors 🔍
  Extend with GitHub Security Advisories or Exploit DB integration 🧩
  Track remediation status and link to patch notes or fixes 🩹

  Troubleshooting

  Common Issues

  Empty results from NVD: Check if your keywords are too narrow or if NVD API rate limits apply 📉
  Google Sheets error: Ensure the Sheet ID and tab names are correct and accessible 🔑
  Alerts not sending: Check Slack webhook or email configurations 🔧

  Getting Help

  Read inline comments in n8n 📝
  Visit the n8n Docs 📚
  Contact template creator: dimejicole21@gmailcom

  This template was created by David Olusola. 🛡️

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

workflow_json:
  {"id":"p9qhykNr1GkMA2EZ","meta":{"instanceId":"2000c64071c20843606b95c63795bb0797c41036047055a6586498e855b96efc"},"name":"AI Lead Machine Pro: Google Maps → Slack → HubSpot → $$$","tags":[],"nodes":[{"id":"f51db375-2b20-4cc8-b2ff-c7dd38ea44fb","name":"Pro Features Overview","type":"n8n-nodes-base.stickyNote","position":[340,-160],"parameters":{"content":""},"typeVersion":1},{"id":"2c14712d-53ef-4560-b17a-519547a41496","name":"🔧 Configuration Hub","type":"n8n-nodes-base.set","position":[560,480],"parameters":{},"typeVersion":3.4},{"id":"e088f048-b8b6-468b-96c5-dca5665f369c","name":"▶️ Start Lead Generation","type":"n8n-nodes-base.manualTrigger","position":[340,480],"parameters":{},"typeVersion":1},{"id":"078bf509-eb35-4c6c-ad20-45b30fe471a6","name":"🗺️ Google Maps Scraper","type":"n8n-nodes-base.httpRequest","position":[780,380],"parameters":{},"typeVersion":1},{"id":"abfdea1e-2dd6-4efd-bf0a-18c23bfd4a04","name":"📞 Yellow Pages Scraper","type":"n8n-nodes-base.httpRequest","position":[780,580],"parameters":{},"typeVersion":1},{"id":"71beb6cb-003e-4d23-9a9b-20ccb01d029e","name":"🧹 Advanced Data Cleaner","type":"n8n-nodes-base.code","position":[1000,480],"parameters":{},"typeVersion":2},{"id":"9d245511-ad40-4b54-96b9-464c202c06e1","name":"✉️ Email Verification","type":"n8n-nodes-base.httpRequest","position":[1220,480],"parameters":{},"typeVersion":1},{"id":"eefb6f7a-a9ab-4196-98dc-ad481481bdd9","name":"💎 Lead Enrichment Engine","type":"n8n-nodes-base.code","position":[1820,480],"parameters":{},"typeVersion":2},{"id":"e0430047-8e9d-4599-ae59-f16e4dd18b51","name":"🎯 Quality Filter","type":"n8n-nodes-base.if","position":[2040,280],"parameters":{},"typeVersion":2},{"id":"e03c266c-3a1b-40fd-b78e-34bddca75d33","name":"📊 Export Qualified Leads","type":"n8n-nodes-base.googleSheets","position":[2260,180],"parameters":{},"typeVersion":4.5},{"id":"f82e1140-5dfb-438d-80e4-c0ccd17e0592","name":"📋 Export All Leads","type":"n8n-nodes-base.googleSheets","position":[2040,480],"parameters":{},"typeVersion":4.5},{"id":"bbfdc2c9-57f6-442c-bef8-1df8c3cfa944","name":"🏢 Create HubSpot Contact","type":"n8n-nodes-base.hubspot","position":[2480,180],"parameters":{},"typeVersion":2},{"id":"1910bdc8-1ebe-49de-aa4e-10a840d9abc1","name":"🔔 Slack Alert","type":"n8n-nodes-base.slack","position":[2260,380],"webhookId":"b48cae2d-ddfe-4835-b1fd-b1c4c3f95e51","parameters":{},"typeVersion":2.2},{"id":"404ed54d-9316-4d7f-8af3-8d0503e3507a","name":"📈 Analytics Engine","type":"n8n-nodes-base.code","position":[2040,680],"parameters":{},"typeVersion":2},{"id":"e3cc2e40-c78f-41bf-b5f1-89e2b11899f1","name":"📊 Export Analytics","type":"n8n-nodes-base.googleSheets","position":[2260,680],"parameters":{},"typeVersion":4.5},{"id":"d12384ce-c646-461a-9ab1-6202127a1fcc","name":"🤖 AI Lead Qualification","type":"@n8n/n8n-nodes-langchain.openAi","position":[1440,480],"parameters":{},"typeVersion":1.8}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"44f03ae5-3c6f-4dde-a44d-189e2be57148","connections":{"🎯 Quality Filter":{"main":[[{"node":"📊 Export Qualified Leads","type":"main","index":0},{"node":"🔔 Slack Alert","type":"main","index":0}]]},"📈 Analytics Engine":{"main":[[{"node":"📊 Export Analytics","type":"main","index":0}]]},"🔧 Configuration Hub":{"main":[[{"node":"🗺️ Google Maps Scraper","type":"main","index":0},{"node":"📞 Yellow Pages Scraper","type":"main","index":0},{"node":"💎 Lead Enrichment Engine","type":"main","index":0}]]},"✉️ Email Verification":{"main":[[{"node":"🤖 AI Lead Qualification","type":"main","index":0}]]},"📞 Yellow Pages Scraper":{"main":[[{"node":"🧹 Advanced Data Cleaner","type":"main","index":0}]]},"🤖 AI Lead Qualification":{"main":[[{"node":"💎 Lead Enrichment Engine","type":"main","index":0}]]},"🧹 Advanced Data Cleaner":{"main":[[{"node":"✉️ Email Verification","type":"main","index":0}]]},"💎 Lead Enrichment Engine":{"main":[[{"node":"🎯 Quality Filter","type":"main","index":0},{"node":"📋 Export All Leads","type":"main","index":0},{"node":"📈 Analytics Engine","type":"main","index":0}]]},"📊 Export Qualified Leads":{"main":[[{"node":"🏢 Create HubSpot Contact","type":"main","index":0}]]},"🗺️ Google Maps Scraper":{"main":[[{"node":"🧹 Advanced Data Cleaner","type":"main","index":0}]]},"▶️ Start Lead Generation":{"main":[[{"node":"🔧 Configuration Hub","type":"main","index":0}]]}}}


name: AI-Powered WhatsApp Chatbot for Text, Voice, Images, and PDF with RAG
author_name: NovaNode
author_username: thomasgpt
categories: []
created_at: 2025-06-09T22:22:54.378Z
updated_at: 2025-06-09T22:22:54.378Z
url: https://n8n.io/workflows/4827
scraped_at: 2025-06-19 22:48:34
description:
  Who is this for?
  This template is designed for internal support teams, product specialists, and knowledge managers in technology companies who want to automate ingestion of product documentation and enable AI-driven, retrieval-augmented question answering via WhatsApp.

  What problem is this workflow solving?
  Support agents often spend too much time manually searching through lengthy documentation, leading to inconsistent or delayed answers. This solution automates importing, chunking, and indexing product manuals, then uses retrieval-augmented generation (RAG) to answer user queries accurately and quickly with AI via WhatsApp messaging.

  What these workflows do

  Workflow 1: Document Ingestion & Indexing

  Manually triggered to import product documentation from Google Docs.
  Automatically splits large documents into chunks for efficient searching.
  Generates vector embeddings for each chunk using OpenAI embeddings.
  Inserts the embedded chunks and metadata into a MongoDB Atlas vector store, enabling fast semantic search.

  Workflow 2: AI-Powered Query & Response via WhatsApp

  Listens for incoming WhatsApp user messages, supporting various types:
  	Text messages: Plain text queries from users.
  	Audio messages: Voice notes transcribed into text for processing.
  	Image messages: Photos or screenshots analyzed to provide contextual answers.
  	Document messages: PDFs, spreadsheets, or other files parsed for relevant content.
  Converts incoming queries to vector embeddings and performs similarity search on the MongoDB vector store.
  Uses OpenAI’s GPT-4o-mini model with retrieval-augmented generation to produce concise, context-aware answers.
  Maintains conversation context across multiple turns using a memory buffer node.
  Routes different message types to appropriate processing nodes to maximize answer quality.

  Setup

  Setting up vector embeddings

  Authenticate Google Docs and connect your Google Docs URL containing the product documentation you want to index.
  Authenticate MongoDB Atlas and connect the collection where you want to store the vector embeddings. Create a search index on this collection to support vector similarity queries.
  Ensure the index name matches the one configured in n8n (data_index).
  See the example MongoDB search index template below for reference.

  Setting up chat

  Authenticate the WhatsApp node with your Meta account credentials to enable message receiving and sending.
  Connect the MongoDB collection containing embedded product documentation to the MongoDB Vector Search node used for similarity queries.
  Set up the system prompt in the Knowledge Base Agent node to reflect your company’s tone, answering style, and any business rules, ensuring it references the connected MongoDB collection for context retrieval.

  Make sure

  Both MongoDB nodes (in ingestion and chat workflows) are connected to the same collection with:

  An embedding field storing vector data,

  Relevant metadata fields (e.g., document ID, source), and

  The same vector index name configured (e.g., data_index).

  Search Index Example:

  {
    "mappings": {
      "dynamic": false,
      "fields": {
        "_id": { "type": "string" },
        "text": { "type": "string" },
        "embedding": {
          "type": "knnVector",
          "dimensions": 1536,
          "similarity": "cosine"
        },
        "source": { "type": "string" },
        "doc_id": { "type": "string" }
      }
    }
  }

nodes_used:
  ["n8n-nodes-base.httpRequest","n8n-nodes-base.googleDocs","n8n-nodes-base.whatsApp","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.embeddingsOpenAi","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryBufferWindow","@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter","@n8n/n8n-nodes-langchain.documentDefaultDataLoader","@n8n/n8n-nodes-langchain.openAi","@n8n/n8n-nodes-langchain.vectorStoreMongoDBAtlas"]

workflow_json:
  {"meta":{"instanceId":"074f90e2bb5206c5f405a8aac6551497c72005283a5405fb08207b1b3a78c2b8","templateCredsSetupCompleted":true},"nodes":[{"id":"d1b47f60-5a4d-4629-a18d-b3c6ec0c972c","name":"Knowledge Base Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[3720,400],"parameters":{"text":"={{ $json.text }}","options":{"systemMessage":""},"promptType":"define"},"typeVersion":1.9},{"id":"c36731ce-5086-4a2f-8c3a-63be150fb8ae","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[3720,580],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"cJRah9hGPQ7eX4jd","name":"OpenAi account"}},"typeVersion":1.2},{"id":"53c2496a-0737-452c-b49c-ca0afa9c0073","name":"Embeddings OpenAI","type":"@n8n/n8n-nodes-langchain.embeddingsOpenAi","position":[4060,740],"parameters":{"options":{}},"credentials":{"openAiApi":{"id":"cJRah9hGPQ7eX4jd","name":"OpenAi account"}},"typeVersion":1.2},{"id":"54697b14-28a0-4572-b17e-328a7b52cc90","name":"When clicking \"Execute Workflow\"","type":"n8n-nodes-base.manualTrigger","position":[1380,-560],"parameters":{},"typeVersion":1},{"id":"a79b9b58-0211-4570-af84-64db8bef9de3","name":"Simple Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[3820,580],"parameters":{"sessionKey":"=memory_{{ $('WhatsApp Trigger').item.json.contacts[0].wa_id }}","sessionIdType":"customKey"},"typeVersion":1.3},{"id":"fda97aec-70be-4611-94a3-7816e384c76b","name":"MongoDB Vector Search","type":"@n8n/n8n-nodes-langchain.vectorStoreMongoDBAtlas","position":[3940,580],"parameters":{"mode":"retrieve-as-tool","options":{},"toolName":"productDocs","mongoCollection":{"__rl":true,"mode":"list","value":"n8n-template","cachedResultName":"n8n-template"},"toolDescription":"retreive documentation","vectorIndexName":"data_index"},"credentials":{"mongoDb":{"id":"7riubYENUDZsmjyK","name":"MongoDB account 2"}},"typeVersion":1.1},{"id":"8cf54cb6-7247-4036-b1e4-9a28650d700a","name":"Document Section Loader","type":"@n8n/n8n-nodes-langchain.documentDefaultDataLoader","position":[1920,-400],"parameters":{"options":{"metadata":{"metadataValues":[{"name":"doc_id","value":"={{ $json.documentId }}"}]}},"jsonData":"={{ $json.content }}","jsonMode":"expressionData"},"typeVersion":1},{"id":"4e93e3c3-1847-483a-b6a7-67ff2cff294f","name":"Document Chunker","type":"@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter","position":[1920,-260],"parameters":{"options":{"splitCode":"markdown"},"chunkSize":3000,"chunkOverlap":200},"typeVersion":1},{"id":"4f616bfc-4ec7-4c88-8a63-cb2c47655680","name":"MongoDB Vector Store Inserter","type":"@n8n/n8n-nodes-langchain.vectorStoreMongoDBAtlas","position":[1820,-560],"parameters":{"mode":"insert","options":{},"mongoCollection":{"__rl":true,"mode":"list","value":"n8n-template","cachedResultName":"n8n-template"},"vectorIndexName":"data_index"},"credentials":{"mongoDb":{"id":"7riubYENUDZsmjyK","name":"MongoDB account 2"}},"typeVersion":1.1},{"id":"cc9a0766-69a4-4745-97f5-4c4c5e156c91","name":"OpenAI Embeddings Generator","type":"@n8n/n8n-nodes-langchain.embeddingsOpenAi","position":[1820,-400],"parameters":{"options":{}},"credentials":{"openAiApi":{"id":"cJRah9hGPQ7eX4jd","name":"OpenAi account"}},"typeVersion":1.2},{"id":"a9368d23-e35f-4986-8060-30a05f3f9c05","name":"Google Docs Importer","type":"n8n-nodes-base.googleDocs","position":[1600,-560],"parameters":{"operation":"get","documentURL":"https://docs.google.com/document/d/1gvgp71e9edob8WLqFIYCdzC7kUq3pLO37VKb-a-vVW4/edit?tab=t.0"},"credentials":{"googleDocsOAuth2Api":{"id":"FNXMwqMf7vl1WUFj","name":"Google Docs account"}},"typeVersion":2},{"id":"1fb0f8a3-9113-4185-a935-0fc327f70881","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[1000,-580],"parameters":{"color":5,"content":"Run this workflow manually to import and index Google Docs product documentation into MongoDB with vector embeddings for fast search."},"typeVersion":1},{"id":"62e13275-6f92-4799-9cbe-e0064ceb5140","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[1000,360],"parameters":{"color":4,"height":280,"content":"This workflow listens for WhatsApp messages (text, audio, image, documents), converts them into embeddings, searches MongoDB, and uses GPT-4o-mini to provide context-aware answers with conversation memory."},"typeVersion":1},{"id":"d21fc408-f66d-4b07-972a-811aa420b4ce","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[2220,-580],"parameters":{"height":540,"content":"Search Index Example \n\n{\n  \"mappings\": {\n    \"dynamic\": false,\n    \"fields\": {\n      \"_id\": {\n        \"type\": \"string\"\n      },\n      \"text\": {\n        \"type\": \"string\"\n      },\n      \"embedding\": {\n        \"type\": \"knnVector\",\n        \"dimensions\": 1536,\n        \"similarity\": \"cosine\"\n      },\n      \"source\": {\n        \"type\": \"string\"\n      },\n      \"doc_id\": {\n        \"type\": \"string\"\n      }\n    }\n  }\n}\n"},"typeVersion":1},{"id":"ddc0fdb7-bacc-4f41-87bf-48bb714a404d","name":"WhatsApp Trigger","type":"n8n-nodes-base.whatsAppTrigger","position":[1380,400],"webhookId":"ab09ca3e-53b2-4079-9ddc-bccb2f69551b","parameters":{"options":{},"updates":["messages"]},"credentials":{"whatsAppTriggerApi":{"id":"eb1MSQfEla9dGghs","name":"WhatsApp OAuth account"}},"typeVersion":1},{"id":"8842d0c7-082e-4b4e-b350-a8bb8f47c390","name":"OpenAI","type":"@n8n/n8n-nodes-langchain.openAi","position":[2460,160],"parameters":{"options":{},"resource":"audio","operation":"translate"},"credentials":{"openAiApi":{"id":"cJRah9hGPQ7eX4jd","name":"OpenAi account"}},"typeVersion":1.8},{"id":"a342dc14-0ffe-41ba-a3e9-853fe043f4fb","name":"OpenAI1","type":"@n8n/n8n-nodes-langchain.openAi","position":[2460,400],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"GPT-4O-MINI"},"options":{"detail":"auto"},"resource":"image","inputType":"base64","operation":"analyze"},"credentials":{"openAiApi":{"id":"cJRah9hGPQ7eX4jd","name":"OpenAi account"}},"typeVersion":1.8},{"id":"b1220587-fadf-4b5b-944e-b6e60b64c141","name":"Extract from PDF","type":"n8n-nodes-base.extractFromFile","position":[3060,860],"parameters":{"options":{},"operation":"pdf"},"typeVersion":1},{"id":"b02474a0-be6a-4591-a10c-abc2f597a3e6","name":"Extract from XLS","type":"n8n-nodes-base.extractFromFile","position":[2960,1060],"parameters":{"options":{},"operation":"xls"},"typeVersion":1},{"id":"1012f8a7-9fcb-4d80-ad5f-bfaa31eddf7d","name":"Extract from XLSX","type":"n8n-nodes-base.extractFromFile","position":[2960,1220],"parameters":{"options":{},"operation":"xlsx","binaryPropertyName":"=data"},"typeVersion":1},{"id":"8891a2eb-16d6-471a-803e-df1789a336f3","name":"Map JSON","type":"n8n-nodes-base.set","position":[3200,980],"parameters":{"options":{},"assignments":{"assignments":[{"id":"72ae0d20-616a-4a65-9b14-53bf53656091","name":"data","type":"string","value":"={{ $json }}"}]}},"typeVersion":3.4},{"id":"a0920bc7-71bd-4803-bbce-4cef14cac5ee","name":"Map file extensions","type":"n8n-nodes-base.code","position":[2420,740],"parameters":{"jsCode":"let requests = $(\"Download Document\").all()\n\nrequests.forEach((request) => {\n  let mime_type = request.json.mime_type\n\n  if (\n    mime_type === \"text/calendar\" || \n    mime_type === \"application/ics\" || \n    mime_type === \"text/x-calendar\"\n  ) {\n    request.json.mime_type = \"mapped/calendar\"\n  }\n\n  if (\n    mime_type === \"application/xml\" || \n    mime_type === \"text/xml\") {\n    request.json.mime_type = \"mapped/xml\"\n  }\n\n  if (!mime_type) {\n    request.json.mime_type = $('Gets WhatsApp Document Source URL').first().json.mime_type\n  }\n})\n\nreturn requests;"},"typeVersion":2},{"id":"77302aa3-6e87-4de6-9ec7-387ddb76fc84","name":"Map document prompt","type":"n8n-nodes-base.set","position":[3440,800],"parameters":{"options":{},"assignments":{"assignments":[{"id":"da68bcca-a2a6-4676-8649-6fb1b664e44c","name":"text","type":"string","value":"=Parsed text: {{ $json.text || $json.data || $json }}\n\nCaption text: {{ $('Route Types').item.json.messages[0].document.caption }}\n\nMimeType: {{ $('Gets WhatsApp Document Source URL').item.json.mime_type }}"}]}},"typeVersion":3.4},{"id":"90821e49-c98d-4617-8289-1be6d3aeb087","name":"Map image prompt","type":"n8n-nodes-base.set","position":[2680,400],"parameters":{"options":{},"assignments":{"assignments":[{"id":"48af2dcc-4ce9-45fc-abfc-54f803930092","name":"text","type":"string","value":"=User image description: {{ $json.content }}\n\nUser image caption: {{ $('Route Types').item.json.messages[0].image.caption }}"}]}},"typeVersion":3.4},{"id":"cf603f5c-0a6e-4cdd-846b-738ed417daa2","name":"Map text prompt","type":"n8n-nodes-base.set","position":[2020,-40],"parameters":{"options":{},"assignments":{"assignments":[{"id":"38aec976-a32c-4b0e-85f4-c90adc16abc9","name":"text","type":"string","value":"={{ $json.messages[0].text.body }}"}]}},"typeVersion":3.4},{"id":"7727e89d-cf21-4440-ab7f-85594eb1ec44","name":"Gets WhatsApp Voicemail Source URL","type":"n8n-nodes-base.whatsApp","position":[2020,160],"webhookId":"bbe62f3d-8788-49d4-aae6-9e9411446d44","parameters":{"resource":"media","operation":"mediaUrlGet","mediaGetId":"={{ $json.messages[0].audio.id}}"},"credentials":{"whatsAppApi":{"id":"HuYOJ00weACKEFR6","name":"WhatsApp account"}},"typeVersion":1},{"id":"08b938a1-d32e-4aa1-958f-bdabd3dfec13","name":"Gets WhatsApp Image Source URL","type":"n8n-nodes-base.whatsApp","position":[2020,400],"webhookId":"c2982df4-1d8d-4669-a724-44ae17d11e6c","parameters":{"resource":"media","operation":"mediaUrlGet","mediaGetId":"={{ $json.messages[0].image.id }}"},"credentials":{"whatsAppApi":{"id":"HuYOJ00weACKEFR6","name":"WhatsApp account"}},"typeVersion":1},{"id":"d934ce80-cdb0-476d-8896-b8c226086933","name":"Gets WhatsApp Document Source URL","type":"n8n-nodes-base.whatsApp","position":[2020,740],"webhookId":"c2982df4-1d8d-4669-a724-44ae17d11e6c","parameters":{"resource":"media","operation":"mediaUrlGet","mediaGetId":"={{ $json.messages[0].document.id }}"},"credentials":{"whatsAppApi":{"id":"HuYOJ00weACKEFR6","name":"WhatsApp account"}},"typeVersion":1},{"id":"aad1b221-0985-43e7-bc0b-312436171abe","name":"Download Voicemail","type":"n8n-nodes-base.httpRequest","position":[2240,160],"parameters":{"url":"={{ $json.url }}","options":{},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"VZo8qdSLzpZ3qRlq","name":"Header Auth account"}},"typeVersion":4.2},{"id":"dfd08bec-9d30-4125-b167-7feaeefd7afa","name":"Download Image","type":"n8n-nodes-base.httpRequest","position":[2240,400],"parameters":{"url":"={{ $json.url }}","options":{},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"VZo8qdSLzpZ3qRlq","name":"Header Auth account"}},"typeVersion":4.2},{"id":"ba3d221f-ce5c-4105-82cf-fbd11c2c0e2f","name":"Download Document","type":"n8n-nodes-base.httpRequest","position":[2240,740],"parameters":{"url":"={{ $json.url }}","options":{"response":{"response":{}}},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"VZo8qdSLzpZ3qRlq","name":"Header Auth account"}},"typeVersion":4.2},{"id":"87ecc44f-cc1f-47e0-b995-079230be118d","name":"Route Types","type":"n8n-nodes-base.switch","position":[1600,380],"parameters":{"rules":{"values":[{"outputKey":"Text","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"2fc5c912-629b-4cbe-b5e3-7e3f0651c628","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.messages[0].type }}","rightValue":"text"}]},"renameOutput":true},{"outputKey":"Audio","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"26a3d85c-0815-48ff-85ce-713129a1107c","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.messages[0].type }}","rightValue":"audio"}]},"renameOutput":true},{"outputKey":"Image","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"840b95b8-6559-4fb7-b32c-651451d6d0d2","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.messages[0].type }}","rightValue":"image"}]},"renameOutput":true},{"outputKey":"Document","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"3e7a07f9-b785-450c-8c68-f6b276838503","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.messages[0].type }}","rightValue":"document"}]},"renameOutput":true}]},"options":{}},"typeVersion":3.2},{"id":"ce3d08ce-4445-4473-90b2-227ba065c4d8","name":"Route Document Types","type":"n8n-nodes-base.switch","position":[2680,580],"parameters":{"rules":{"values":[{"outputKey":"CSV","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"14e23243-cd44-4cb1-99bd-9e6905d511ad","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.mime_type }}","rightValue":"text/csv"}]},"renameOutput":true},{"outputKey":"HTML","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"6d7616c5-6bdd-47b7-923e-639491d15a4e","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.mime_type }}","rightValue":"text/html"}]},"renameOutput":true},{"outputKey":"Calendar","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"a2174e02-378a-41ff-b269-61f4fc3f1de9","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.mime_type }}","rightValue":"=mapped/calendar"}]},"renameOutput":true},{"outputKey":"RTF","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"f3b406d7-362d-473e-8edd-c3e5f2d9c44c","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.mime_type }}","rightValue":"text/rtf"}]},"renameOutput":true},{"outputKey":"TXT","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"64dd4658-54e7-4453-adbc-7067dffcd555","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.mime_type }}","rightValue":"text/plain"}]},"renameOutput":true},{"outputKey":"XML","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"7540a3ab-b48e-4bec-94e9-a5dfc3d65a4c","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.mime_type }}","rightValue":"mapped/xml"}]},"renameOutput":true},{"outputKey":"PDF","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"88b618fd-9a88-491e-91dd-c5fc9efa36e3","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.mime_type }}","rightValue":"application/pdf"}]},"renameOutput":true},{"outputKey":"JSON","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"9c4d90aa-b4ea-4a63-b15e-666899c8360e","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.mime_type }}","rightValue":"application/json"}]},"renameOutput":true},{"outputKey":"XLS","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"9baa7c88-3950-4099-8498-99a4640b95e7","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.mime_type }}","rightValue":"application/vnd.ms-excel"}]},"renameOutput":true},{"outputKey":"XLSX","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"b83e540c-ba1e-42d0-ac83-f675e25e6aea","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.mime_type }}","rightValue":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}]},"renameOutput":true},{"outputKey":"ELSE","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"ea3be820-2ead-4ec2-b292-42d3c7804b55","operator":{"type":"string","operation":"exists","singleValue":true},"leftValue":"={{ $json.mime_type }}","rightValue":""}]},"renameOutput":true}]},"options":{}},"typeVersion":3.2},{"id":"18684032-23ec-4e10-88f4-e93363432a67","name":"Send Unsupported Response","type":"n8n-nodes-base.whatsApp","position":[2960,1380],"webhookId":"017d267f-4897-4726-bf03-304ef10352bf","parameters":{"textBody":"=The File type you provided is unsupported.","operation":"send","phoneNumberId":"677680658761861","additionalFields":{},"recipientPhoneNumber":"={{ $('WhatsApp Trigger').item.json.messages[0].from }}"},"credentials":{"whatsAppApi":{"id":"HuYOJ00weACKEFR6","name":"WhatsApp account"}},"typeVersion":1},{"id":"acc8e4ae-0610-42fc-a318-b9a23a38919b","name":"Send Response","type":"n8n-nodes-base.whatsApp","position":[4080,400],"webhookId":"23834751-5066-48ba-8e19-549680df2b27","parameters":{"textBody":"={{ $json.output }}","operation":"send","phoneNumberId":"677680658761861","additionalFields":{},"recipientPhoneNumber":"={{ $('WhatsApp Trigger').item.json.messages[0].from }}"},"credentials":{"whatsAppApi":{"id":"HuYOJ00weACKEFR6","name":"WhatsApp account"}},"typeVersion":1}],"pinData":{},"connections":{"OpenAI":{"main":[[{"node":"Knowledge Base Agent","type":"main","index":0}]]},"OpenAI1":{"main":[[{"node":"Map image prompt","type":"main","index":0}]]},"Map JSON":{"main":[[{"node":"Map document prompt","type":"main","index":0}]]},"Route Types":{"main":[[{"node":"Map text prompt","type":"main","index":0}],[{"node":"Gets WhatsApp Voicemail Source URL","type":"main","index":0}],[{"node":"Gets WhatsApp Image Source URL","type":"main","index":0}],[{"node":"Gets WhatsApp Document Source URL","type":"main","index":0}]]},"Simple Memory":{"ai_memory":[[{"node":"Knowledge Base Agent","type":"ai_memory","index":0}]]},"Download Image":{"main":[[{"node":"OpenAI1","type":"main","index":0}]]},"Map text prompt":{"main":[[{"node":"Knowledge Base Agent","type":"main","index":0}]]},"Document Chunker":{"ai_textSplitter":[[{"node":"Document Section Loader","type":"ai_textSplitter","index":0}]]},"Extract from PDF":{"main":[[{"node":"Map document prompt","type":"main","index":0}]]},"Extract from XLS":{"main":[[{"node":"Map JSON","type":"main","index":0}]]},"Map image prompt":{"main":[[{"node":"Knowledge Base Agent","type":"main","index":0}]]},"WhatsApp Trigger":{"main":[[{"node":"Route Types","type":"main","index":0}]]},"Download Document":{"main":[[{"node":"Map file extensions","type":"main","index":0}]]},"Embeddings OpenAI":{"ai_embedding":[[{"node":"MongoDB Vector Search","type":"ai_embedding","index":0}]]},"Extract from XLSX":{"main":[[{"node":"Map JSON","type":"main","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Knowledge Base Agent","type":"ai_languageModel","index":0}]]},"Download Voicemail":{"main":[[{"node":"OpenAI","type":"main","index":0}]]},"Map document prompt":{"main":[[{"node":"Knowledge Base Agent","type":"main","index":0}]]},"Map file extensions":{"main":[[{"node":"Route Document Types","type":"main","index":0}]]},"Google Docs Importer":{"main":[[{"node":"MongoDB Vector Store Inserter","type":"main","index":0}]]},"Knowledge Base Agent":{"main":[[{"node":"Send Response","type":"main","index":0}]]},"Route Document Types":{"main":[[{"node":"Map document prompt","type":"main","index":0}],[{"node":"Map document prompt","type":"main","index":0}],[{"node":"Map document prompt","type":"main","index":0}],[{"node":"Map document prompt","type":"main","index":0}],[{"node":"Map document prompt","type":"main","index":0}],[{"node":"Map document prompt","type":"main","index":0}],[{"node":"Extract from PDF","type":"main","index":0}],[{"node":"Map JSON","type":"main","index":0}],[{"node":"Extract from XLS","type":"main","index":0}],[{"node":"Extract from XLSX","type":"main","index":0}],[{"node":"Send Unsupported Response","type":"main","index":0}]]},"MongoDB Vector Search":{"ai_tool":[[{"node":"Knowledge Base Agent","type":"ai_tool","index":0}]]},"Document Section Loader":{"ai_document":[[{"node":"MongoDB Vector Store Inserter","type":"ai_document","index":0}]]},"Send Unsupported Response":{"main":[[]]},"OpenAI Embeddings Generator":{"ai_embedding":[[{"node":"MongoDB Vector Store Inserter","type":"ai_embedding","index":0}]]},"Gets WhatsApp Image Source URL":{"main":[[{"node":"Download Image","type":"main","index":0}]]},"When clicking \"Execute Workflow\"":{"main":[[{"node":"Google Docs Importer","type":"main","index":0}]]},"Gets WhatsApp Document Source URL":{"main":[[{"node":"Download Document","type":"main","index":0}]]},"Gets WhatsApp Voicemail Source URL":{"main":[[{"node":"Download Voicemail","type":"main","index":0}]]}}}


name: Realtime Job Description & Salary Extraction using Bright Data MCP & OpenAI 4o mini
author_name: Ranjan Dailata
author_username: ranjancse
categories: []
created_at: 2025-06-09T23:19:37.813Z
updated_at: 2025-06-09T23:19:37.813Z
url: https://n8n.io/workflows/4829
scraped_at: 2025-06-19 22:49:32
description:
  Notice
  Community nodes can only be installed on self-hosted instances of n8n.

  Who this is for

  This workflow automates the real-time extraction of Job Descriptions and Salary Information from job listing pages using Bright Data MCP and analyzes content using OpenAI GPT-4o mini. 

  This workflow is ideal for:

  Recruiters & HR Tech Startups**: Automate job data collection from public listings

  Market Intelligence Teams**: Analyze compensation trends across companies or geographies

  Job Boards & Aggregators**: Power search results with structured, enriched listings

  AI Workflow Builders**: Extend to other career platforms or automate resume-job match analysis

  Analysts & Researchers**: Track hiring signals and salary benchmarks in real time

  What problem is this workflow solving?

  Traditional scraping of job portals can be challenging due to cluttered content, anti-scraping measures, and inconsistent formatting. Manually analyzing salary ranges and job descriptions is tedious and error-prone.

  This workflow solves the problem by:

  Simulating user behavior using Bright Data MCP Client to bypass anti-scraping systems

  Extracting structured, clean job data in Markdown format

  Using OpenAI GPT-4o mini to analyze and extract precise salary details and refined job descriptions

  Merging and formatting the result for easy consumption

  Delivering final output via webhook, Google Sheets, or file system

  What this workflow does

  Components & Flow

  Input Nodes
  job_search_url: The job listing or search result URL

  job_role: The title or role being searched for (used in logging/formatting)

  MCP Client Operations
  MCP Salary Data Extractor

  	Simulates browser behavior and scrapes salary-related content (if available)

  	MCP Job Description Extractor

  Extracts full job description as structured Markdown content

  OpenAI GPT-4o mini Nodes

  Salary Information Extractor

  Uses GPT-4o mini to detect, clean, and standardize salary range data (if any)

  Job Description Refiner

  Extracts role responsibilities, qualifications, and benefits from unstructured text

  Merge Node
  Combines the refined job description and extracted salary information into a unified JSON response object

  Aggregate node
  Aggregates the job description and salary information into a single JSON response object

  Final Output Handling

  The output is handled in three different formats depending on your downstream needs:

  Save to Disk**

  	Output stored with filename including timestamp and job role

  Google Sheet Update**

  	Adds a new row with job role, salary, summary, and link

  Webhook Notification**

  	Pushes merged response to an external system

  Pre-conditions

  Knowledge of Model Context Protocol (MCP) is highly essential. Please read this blog post - model-context-protocol
  You need to have the Bright Data account and do the necessary setup as mentioned in the Setup section below.
  You need to have the Google Gemini API Key. Visit Google AI Studio
  You need to install the Bright Data MCP Server @brightdata/mcp
  You need to install the n8n-nodes-mcp

  Setup

  Please make sure to setup n8n locally with MCP Servers by navigating to n8n-nodes-mcp
  Please make sure to install the Bright Data MCP Server @brightdata/mcp  on your local machine.
  Sign up at Bright Data.
  Navigate to Proxies & Scraping and create a new Web Unlocker zone by selecting Web Unlocker API under Scraping Solutions.
  Create a Web Unlocker proxy zone called mcp_unlocker on Bright Data control panel.
  In n8n, configure the OpenAi account credentials.
  In n8n, configure the credentials to connect with MCP Client (STDIO) account with the Bright Data MCP Server as shown below.



  Make sure to copy the Bright Data API_TOKEN within the Environments textbox above as API_TOKEN=&lt;your-token&gt;

  How to customize this workflow to your needs

  Modify Input Source

  Change the job_search_url to point to any job board or aggregator

  Customize job_role to reflect the type of jobs being analyzed

  Tweak LLM Prompts (Optional)

  Refine GPT-4o mini prompts to extract additional fields like benefits, tech stacks, remote eligibility

  Change Output Format

  Customize the merged object to output JSON, CSV, or Markdown based on downstream needs

  Add additional destinations (e.g., Slack, Airtable, Notion) via n8n nodes

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

workflow_json:
  {"id":"LTw3TlYxQXEMSTi3","meta":{"instanceId":"885b4fb4a6a9c2cb5621429a7b972df0d05bb724c20ac7dac7171b62f1c7ef40","templateCredsSetupCompleted":true},"name":"Real-time Extract of Job Description, Salary Details via Bright Data MCP & OpenAI 4o mini","tags":[{"id":"ZOwtAMLepQaGW76t","name":"Building Blocks","createdAt":"2025-04-13T15:23:40.462Z","updatedAt":"2025-04-13T15:23:40.462Z"},{"id":"ddPkw7Hg5dZhQu2w","name":"AI","createdAt":"2025-04-13T05:38:08.053Z","updatedAt":"2025-04-13T05:38:08.053Z"},{"id":"rKOa98eAi3IETrLu","name":"HR","createdAt":"2025-04-13T04:59:30.580Z","updatedAt":"2025-04-13T04:59:30.580Z"}],"nodes":[{"id":"c3aaad9e-db7d-4761-9e34-99483f302562","name":"When clicking ‘Test workflow’","type":"n8n-nodes-base.manualTrigger","position":[-660,-180],"parameters":{},"typeVersion":1},{"id":"3bf2f1f2-5303-45ce-9c12-76597b4e82fa","name":"Bright Data MCP Client List Tools","type":"n8n-nodes-mcp.mcpClient","position":[-440,-180],"parameters":{},"credentials":{"mcpClientApi":{"id":"JtatFSfA2kkwctYa","name":"MCP Client (STDIO) account"}},"typeVersion":1},{"id":"6489766a-b657-4a2f-8a3d-fc4aea3b11d2","name":"Set input fields","type":"n8n-nodes-base.set","position":[-220,-180],"parameters":{"options":{},"assignments":{"assignments":[{"id":"0ac91db2-9848-40d4-b942-cd7288597ded","name":"job_search_url","type":"string","value":"https://www.indeed.com/viewjob?jk=075f6b95d1ae92ae"},{"id":"f5b7e10d-bcd8-439c-8e84-ba4af11f2cd2","name":"job_role","type":"string","value":"Lead Backend .Net Developer Dallas, TX Hybrid work"},{"id":"e601ea9e-20ab-40ed-82ec-89b895b07f85","name":"webhook_notification_url","type":"string","value":"https://webhook.site/c9118da2-1c54-460f-a83a-e5131b7098db"}]}},"typeVersion":3.4},{"id":"f6a345dd-40a3-4a94-ba65-18698694a8bc","name":"MCP Client for Job Data Extract with Markdown","type":"n8n-nodes-mcp.mcpClient","position":[20,-180],"parameters":{"toolName":"scrape_as_markdown","operation":"executeTool","toolParameters":"={\n  \"url\": \"{{ $json.job_search_url }}\"\n} "},"credentials":{"mcpClientApi":{"id":"JtatFSfA2kkwctYa","name":"MCP Client (STDIO) account"}},"typeVersion":1},{"id":"53495c35-ca3a-4874-a0a3-2cd9965a9638","name":"MCP Client for Salary Data Extraction","type":"n8n-nodes-mcp.mcpClient","position":[20,-540],"parameters":{"toolName":"search_engine","operation":"executeTool","toolParameters":"={\n  \"query\": \"{{ $json.job_role }}\",\n  \"engine\": \"google\"\n} "},"credentials":{"mcpClientApi":{"id":"JtatFSfA2kkwctYa","name":"MCP Client (STDIO) account"}},"typeVersion":1},{"id":"25668caa-6981-4f57-9eae-ba5c29374e56","name":"Salary Information Extractor","type":"@n8n/n8n-nodes-langchain.informationExtractor","position":[260,-540],"parameters":{"text":"=Extract the salary information from the following content  {{ $json.result.content[0].text }}","options":{},"schemaType":"manual","inputSchema":"{\n  \"$schema\": \"http://json-schema.org/schema#\",\n  \"title\": \"Salary Information\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"job_title\": {\n      \"type\": \"string\",\n      \"description\": \"The official title of the job (e.g., Software Engineer, DevOps Engineer)\"\n    },\n    \"job_level\": {\n      \"type\": \"string\",\n      \"description\": \"The seniority level (e.g., Junior, Mid, Senior, Lead, Principal)\",\n      \"enum\": [\"Intern\", \"Junior\", \"Mid\", \"Senior\", \"Lead\", \"Principal\", \"Director\", \"VP\", \"C-Level\"]\n    },\n    \"company_name\": {\n      \"type\": \"string\",\n      \"description\": \"The name of the company offering the position\"\n    },\n    \"location\": {\n      \"type\": \"string\",\n      \"description\": \"City and state/country of the job\"\n    },\n    \"employment_type\": {\n      \"type\": \"string\",\n      \"description\": \"Full-time, Part-time, Contract, Freelance, Internship\",\n      \"enum\": [\"Full-time\", \"Part-time\", \"Contract\", \"Freelance\", \"Internship\"]\n    },\n    \"remote_option\": {\n      \"type\": \"string\",\n      \"description\": \"Remote status of the job\",\n      \"enum\": [\"On-site\", \"Hybrid\", \"Remote\"]\n    },\n    \"currency\": {\n      \"type\": \"string\",\n      \"description\": \"Currency code (e.g., USD, EUR, INR)\"\n    },\n    \"salary_min\": {\n      \"type\": \"number\",\n      \"description\": \"Minimum base salary offered\"\n    },\n    \"salary_max\": {\n      \"type\": \"number\",\n      \"description\": \"Maximum base salary offered\"\n    },\n    \"salary_period\": {\n      \"type\": \"string\",\n      \"description\": \"Salary frequency\",\n      \"enum\": [\"hour\", \"day\", \"week\", \"month\", \"year\"]\n    },\n    \"equity\": {\n      \"type\": \"string\",\n      \"description\": \"Equity component of the compensation (e.g., '0.1%', '$5,000 in stock')\",\n      \"nullable\": true\n    },\n    \"bonus\": {\n      \"type\": \"string\",\n      \"description\": \"Bonus component (e.g., '10% performance bonus', '$5000 sign-on')\",\n      \"nullable\": true\n    },\n    \"skills_required\": {\n      \"type\": \"array\",\n      \"description\": \"Key technical or soft skills expected\",\n      \"items\": {\n        \"type\": \"string\"\n      }\n    },\n    \"experience_required\": {\n      \"type\": \"string\",\n      \"description\": \"Experience required in years or description (e.g., '3-5 years', 'Entry level')\"\n    },\n    \"posting_source\": {\n      \"type\": \"string\",\n      \"description\": \"Source of the job posting (e.g., LinkedIn, Glassdoor, Indeed)\"\n    },\n    \"posting_date\": {\n      \"type\": \"string\",\n      \"format\": \"date\",\n      \"description\": \"Date when the job was posted\"\n    },\n    \"summary_insight\": {\n      \"type\": \"string\",\n      \"description\": \"Optional Gemini-generated summary or insight (e.g., 'This role offers 15% higher pay than average for the region.')\"\n    }\n  }\n}\n"},"typeVersion":1.1},{"id":"f58be851-947b-4ac7-9afe-b7cefb7a753a","name":"Job Description Extractor","type":"@n8n/n8n-nodes-langchain.informationExtractor","position":[240,-180],"parameters":{"text":"=Extract markdown to textual data.  {{ $json.result.content[0].text }}","options":{},"attributes":{"attributes":[{"name":"job_description","description":"Detailed Job Description in Textual Format"}]}},"typeVersion":1.1},{"id":"9102e1b1-34c8-439d-90c6-6c9d5f8c94b0","name":"Merge the response","type":"n8n-nodes-base.merge","position":[720,-360],"parameters":{},"typeVersion":3.1},{"id":"434f22dc-99d1-465f-8c41-c08060a94137","name":"Create a binary data","type":"n8n-nodes-base.function","position":[1460,-460],"parameters":{"functionCode":"items[0].binary = {\n  data: {\n    data: new Buffer(JSON.stringify(items[0].json, null, 2)).toString('base64')\n  }\n};\nreturn items;"},"typeVersion":1},{"id":"8a9bf6a0-e32d-43de-bb5d-2da34633838f","name":"Webhook Notification for Job Info","type":"n8n-nodes-base.httpRequest","position":[1460,-260],"parameters":{"url":"={{ $('Set input fields').item.json.webhook_notification_url }}","options":{},"sendBody":true,"bodyParameters":{"parameters":[{"name":"response","value":"={{ $json.output.search_response }}"}]}},"typeVersion":4.2},{"id":"bb2ead5d-4188-4b94-af5b-875faf06312d","name":"Write the salary info to disk","type":"n8n-nodes-base.readWriteFile","position":[1700,-460],"parameters":{"options":{},"fileName":"=d:\\JobDesc-SalaryInfo-{{Date.now()}}.json","operation":"write"},"typeVersion":1},{"id":"eeb6d735-7de2-490d-9a3b-1ab3a93990fb","name":"Update Google Sheets","type":"n8n-nodes-base.googleSheets","position":[1460,-40],"parameters":{"columns":{"value":{"output":"={{ $json.output.toJsonString() }}"},"schema":[{"id":"output","type":"string","display":true,"removed":false,"required":false,"displayName":"output","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["output"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"appendOrUpdate","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/10gAihQMT8-h8Mpehe9j-xxN4oTTpg8qwToI-I-Eauew/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"10gAihQMT8-h8Mpehe9j-xxN4oTTpg8qwToI-I-Eauew","cachedResultUrl":"https://docs.google.com/spreadsheets/d/10gAihQMT8-h8Mpehe9j-xxN4oTTpg8qwToI-I-Eauew/edit?usp=drivesdk","cachedResultName":"Salary Info"}},"credentials":{"googleSheetsOAuth2Api":{"id":"Zjoxh2BUZ6VXGQhA","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"aa10d68c-8a90-45e5-867d-cac07f9bd749","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[160,-720],"parameters":{"color":3,"width":440,"height":120,"content":"## Disclaimer\nThis template is only available on n8n self-hosted as it's making use of the community node for MCP Client."},"typeVersion":1},{"id":"1e8d629b-7a62-40e5-b4ed-357daf33b93e","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-300,-820],"parameters":{"color":5,"width":440,"height":220,"content":"## LLM Usages\n\nOpenAI 4o mini LLM is being utilized for the structured data extraction handling."},"typeVersion":1},{"id":"f5b35754-1cd2-41f2-8827-043000f634d0","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-760,-1220],"parameters":{"color":7,"width":440,"height":360,"content":"## Logo\n\n\n![logo](https://images.seeklogo.com/logo-png/43/1/brightdata-logo-png_seeklogo-439974.png)\n"},"typeVersion":1},{"id":"6471bf0f-4c6d-446c-ab68-75d0d8783f0f","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[-760,-820],"parameters":{"width":440,"height":220,"content":"## Note\n\nDeals with the extraction of Job Description and Salary information by leveraging the Bright Data MCP Client.\n\n**Please make sure to set the input fields**"},"typeVersion":1},{"id":"af070520-b6fc-4a76-bef3-32ec82d7132f","name":"OpenAI Chat Model for Salary Info Extract","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[300,-340],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"vPKynKbDzJ5ZU4cU","name":"OpenAi account"}},"typeVersion":1.2},{"id":"10fa3ded-6401-45d7-97ad-1455d41b6794","name":"OpenAI Chat Model for Job Desc Extract","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[340,40],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"vPKynKbDzJ5ZU4cU","name":"OpenAi account"}},"typeVersion":1.2},{"id":"01ddb4ab-73ae-4eef-9f30-4f3438a42823","name":"Aggregate","type":"n8n-nodes-base.aggregate","position":[1020,-360],"parameters":{"options":{},"fieldsToAggregate":{"fieldToAggregate":[{"fieldToAggregate":"output"}]}},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"f52f7f7a-7b6a-4f34-bbf1-c5244974d00b","connections":{"Aggregate":{"main":[[{"node":"Create a binary data","type":"main","index":0},{"node":"Webhook Notification for Job Info","type":"main","index":0},{"node":"Update Google Sheets","type":"main","index":0}]]},"Set input fields":{"main":[[{"node":"MCP Client for Job Data Extract with Markdown","type":"main","index":0},{"node":"MCP Client for Salary Data Extraction","type":"main","index":0}]]},"Merge the response":{"main":[[{"node":"Aggregate","type":"main","index":0}]]},"Create a binary data":{"main":[[{"node":"Write the salary info to disk","type":"main","index":0}]]},"Job Description Extractor":{"main":[[{"node":"Merge the response","type":"main","index":1}]]},"Salary Information Extractor":{"main":[[{"node":"Merge the response","type":"main","index":0}]]},"Bright Data MCP Client List Tools":{"main":[[{"node":"Set input fields","type":"main","index":0}]]},"When clicking ‘Test workflow’":{"main":[[{"node":"Bright Data MCP Client List Tools","type":"main","index":0}]]},"MCP Client for Salary Data Extraction":{"main":[[{"node":"Salary Information Extractor","type":"main","index":0}]]},"OpenAI Chat Model for Job Desc Extract":{"ai_languageModel":[[{"node":"Job Description Extractor","type":"ai_languageModel","index":0}]]},"OpenAI Chat Model for Salary Info Extract":{"ai_languageModel":[[{"node":"Salary Information Extractor","type":"ai_languageModel","index":0}]]},"MCP Client for Job Data Extract with Markdown":{"main":[[{"node":"Job Description Extractor","type":"main","index":0}]]}}}


name: Automate LinkedIn Profile Search & Cold Email Outreach with OpenAI and Hunter
author_name: Abhijay Vuyyuru
author_username: abhijayvuyyuru
categories: []
created_at: 2025-06-10T01:46:22.975Z
updated_at: 2025-06-10T01:46:22.975Z
url: https://n8n.io/workflows/4831
scraped_at: 2025-06-19 22:48:56
description:
  Problem

  🚨 LinkedIn search is BROKEN. 


  I waste hours on LinkedIn manually filtering profiles, reading summaries, hoping they’d reply—tedious, frustrating, inefficient.

  I wish LinkedIn had built an agent that would get me to the right profile with one click!

  If only I could just type:
  "Product managers working on YouTube Shorts' generative AI features."

  and seconds later, have LinkedIn URLs, names, emails, and full context about them.

  Introducing LinkGPT, a LinkedIn Agent, an automated agentic workflow powered by n8n.

  Prerequisites: 
  Required accounts/API keys for Hunter.io, Google, and OpenAI.

  This would be helpful for:

  🎯 Job Seekers: Skip ATS, email hiring managers directly ( I wish I had this when I was recruiting!)

  🎯 Recruiters: Reach your dream candidates first

  🎯 Founders & Sales Teams: Share your demos with customers directly (this does NOT use the expensive Sales Navigator API)

  Step-by-step workflow:

  Takes 5-10 minutes to setup.

  Generate a Boolean search string for LinkedIn profiles.
  Perform authenticated Google searches using your query.
  Extract LinkedIn URLs and workplace context from the search results.
  Use OpenAI to extract first name, last name, and domain name from the context.
  Use Hunter.io to find emails of the contacts.
  Append all results to your connected Google Sheet. Columns: first_name, last_name, domain_name, email, context



  I put together a clear, step-by-step guide on setting this up yourself.

  Sample Query

  Sample:

  Input: "I am headed to NYC later this month, whom should I meet with that works in product management for gen AI products?"

  Output: List of 10 contacts with first name, last name, workplace, email address and context about them so you can email them. 

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

workflow_json:
  {"id":"3hkkh26rGduY5nsP","meta":{"instanceId":"7b22476bf9699de09fe66fed92056e8ae798418cc9901fa9bd85bb46439116b8"},"name":"LinkGPT","tags":[{"id":"V4LdVOYIGIbfdqvb","name":"linkedin","createdAt":"2025-06-11T18:52:18.612Z","updatedAt":"2025-06-11T18:52:18.612Z"},{"id":"yt7Z3T0SDl1Coo7S","name":"hunter","createdAt":"2025-06-11T18:52:25.423Z","updatedAt":"2025-06-11T18:52:25.423Z"},{"id":"qlvLkg4Mxoeos0VK","name":"cold email","createdAt":"2025-06-11T18:52:31.368Z","updatedAt":"2025-06-11T18:52:31.368Z"}],"nodes":[{"id":"95580f35-3039-49e0-9dde-2218080c6c1d","name":"Wait","type":"n8n-nodes-base.wait","position":[760,880],"webhookId":"eadafb7f-61bf-4648-bcdf-b1ffec403f85","parameters":{},"typeVersion":1.1},{"id":"e7ccc8dc-a658-499a-ab69-beed20b418c2","name":"When chat message received","type":"@n8n/n8n-nodes-langchain.chatTrigger","position":[440,400],"webhookId":"1fed76d2-a19a-4c44-aa3d-1bd0aef788bb","parameters":{},"typeVersion":1.1},{"id":"634d67e1-d251-4f9e-994b-642c3346734e","name":"Create a new sheet","type":"n8n-nodes-base.googleSheets","position":[1120,400],"parameters":{},"typeVersion":4.5},{"id":"94a6bc5b-39a7-477b-81ef-ffea2e62284c","name":"Add columns to new sheet","type":"n8n-nodes-base.googleSheets","position":[760,640],"parameters":{},"typeVersion":4.5},{"id":"260d8a51-0708-484b-98ed-9872f110bc2c","name":"set page number for google search","type":"n8n-nodes-base.code","position":[1060,640],"parameters":{},"typeVersion":2},{"id":"92461c5c-1c76-4c0e-b235-f41f952af35e","name":"Google Boolean Search","type":"n8n-nodes-base.httpRequest","position":[1080,880],"parameters":{},"typeVersion":4.2},{"id":"91016b0f-78f2-44a3-900a-c072d7e9ff53","name":"If desired results not reached","type":"n8n-nodes-base.if","position":[400,900],"parameters":{},"typeVersion":2.2},{"id":"235a74ca-b58a-46f4-8de4-a08a83424efc","name":"Appends the results to the sheet","type":"n8n-nodes-base.googleSheets","position":[740,1360],"parameters":{},"typeVersion":4.5},{"id":"3e24720c-39a8-4329-ae6e-c6e01b61b435","name":"Code","type":"n8n-nodes-base.code","position":[4960,600],"parameters":{},"typeVersion":2},{"id":"1db7dcd7-cf17-47f0-b44f-cd612797c88b","name":"Extracts fname, lname, domainname","type":"n8n-nodes-base.code","position":[1080,1140],"parameters":{},"typeVersion":2},{"id":"18bd422d-6fc0-4442-9b2f-a34cd14d45e8","name":"Extracts all linkedin urls and workplace context from the google http response","type":"n8n-nodes-base.code","position":[400,1140],"parameters":{},"typeVersion":2},{"id":"a2c6a9e3-3136-40cc-a58e-23c0b5e78999","name":"Adds 10 to start - Go to next page","type":"n8n-nodes-base.code","position":[100,900],"parameters":{},"typeVersion":2},{"id":"52918647-57a2-4d1c-903c-4cb35429eb4c","name":"Hunter","type":"n8n-nodes-base.hunter","position":[380,1360],"parameters":{},"executeOnce":true,"typeVersion":1},{"id":"140bc853-3ed4-4403-8e98-e24899401633","name":"Generate a Boolean Search String","type":"@n8n/n8n-nodes-langchain.openAi","position":[740,400],"parameters":{},"retryOnFail":false,"typeVersion":1.8},{"id":"85e4341c-50a0-4123-b17f-072898de528a","name":"Extract Contact Details","type":"@n8n/n8n-nodes-langchain.openAi","position":[680,1140],"parameters":{},"typeVersion":1.8},{"id":"79559a98-f857-4c24-a351-0856afa88932","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[1240,880],"parameters":{"content":""},"typeVersion":1},{"id":"e56703f5-b316-41e1-861f-ec4835155df8","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[660,1060],"parameters":{"content":""},"typeVersion":1},{"id":"185dc39c-4c61-445d-9981-30edcc10149a","name":"Columns to add: linkedin_url, first_name, last_name, email, context, domain","type":"n8n-nodes-base.code","position":[420,640],"parameters":{},"typeVersion":2},{"id":"c54825fe-cda7-48af-9d9d-5307ac51bbad","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[720,300],"parameters":{"content":""},"typeVersion":1},{"id":"fa062c54-bdf5-4518-8300-7876657de377","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[640,820],"parameters":{"content":""},"typeVersion":1},{"id":"42eb75e5-6c9e-4890-9248-7051a514ccae","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[60,760],"parameters":{"content":""},"typeVersion":1},{"id":"b180f392-9809-45a8-97f4-3c9a3c0368e1","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[180,1280],"parameters":{"content":""},"typeVersion":1}],"active":true,"pinData":{},"settings":{},"versionId":"19a94125-3580-413b-83dd-3ec7a769e021","connections":{"Code":{"main":[[]]},"Wait":{"main":[[{"node":"Google Boolean Search","type":"main","index":0}]]},"Hunter":{"main":[[{"node":"Appends the results to the sheet","type":"main","index":0}]]},"Create a new sheet":{"main":[[{"node":"Columns to add: linkedin_url, first_name, last_name, email, context, domain","type":"main","index":0}]]},"Google Boolean Search":{"main":[[{"node":"Extracts all linkedin urls and workplace context from the google http response","type":"main","index":0}]]},"Extract Contact Details":{"main":[[{"node":"Extracts fname, lname, domainname","type":"main","index":0}]]},"Add columns to new sheet":{"main":[[{"node":"set page number for google search","type":"main","index":0}]]},"When chat message received":{"main":[[{"node":"Generate a Boolean Search String","type":"main","index":0}]]},"If desired results not reached":{"main":[[{"node":"Wait","type":"main","index":0}],[]]},"Appends the results to the sheet":{"main":[[{"node":"Adds 10 to start - Go to next page","type":"main","index":0}]]},"Generate a Boolean Search String":{"main":[[{"node":"Create a new sheet","type":"main","index":0}]]},"Extracts fname, lname, domainname":{"main":[[{"node":"Hunter","type":"main","index":0}]]},"set page number for google search":{"main":[[{"node":"If desired results not reached","type":"main","index":0}]]},"Adds 10 to start - Go to next page":{"main":[[{"node":"If desired results not reached","type":"main","index":0}]]},"Columns to add: linkedin_url, first_name, last_name, email, context, domain":{"main":[[{"node":"Add columns to new sheet","type":"main","index":0}]]},"Extracts all linkedin urls and workplace context from the google http response":{"main":[[{"node":"Extract Contact Details","type":"main","index":0}]]}}}


name: Multiple Websites Monitoring with Notifications including Phone Calls
author_name: InfyOm Technologies
author_username: infyom
categories: []
created_at: 2025-06-10T05:10:57.984Z
updated_at: 2025-06-10T05:10:57.984Z
url: https://n8n.io/workflows/4833
scraped_at: 2025-06-19 22:48:48
description:
  ✅ What problem does this workflow solve?
  Automatically monitor multiple websites every 5 minutes, log downtime, notify your team instantly via multiple channels, and track uptime/downtime in a Google Sheet—without relying on expensive monitoring tools.

  ⚙️ What does this workflow do?

  Triggers every 5 minutes to monitor website health.
  Fetches a list of website URLs from a Google Sheet.
  Checks the status of each website one by one.
  Sends instant alerts if a website is down (Email, Slack, Telegram, Voice Call).
  Logs downtime events in Google Sheets.
  Tracks when websites are back up and updates the log.
  Sends recovery notifications when a site is live again (Email, Slack, Telegram).

  🔧 Setup

  📄 Google Sheets Setup
  Sheet 1: List of website URLs to monitor.
  Sheet 2: Log to store uptime/downtime records.
  Sample Format: https://docs.google.com/spreadsheets/d/1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY/edit?usp=sharing

  ✉️ Gmail, Slack & Telegram Setup
  Connect Gmail, Slack, and Telegram to n8n.
  Configure each service with proper credentials or OAuth.

  📞 Vapi (Voice Call) Setup
  Create a Vapi account.
  Generate an API key.
  Configure API Parameters (vapi_api_key, assistant_id, number, phone_number_id) on VAPI Node.
  Insert the First Message specified in the Workflow.

  🧠 How it Works

  ⏱ 1. Scheduled Monitoring
  A Schedule Trigger runs the workflow every 5 minutes. It reads the list of URLs from the Google Sheet and loops through each one.

  🌍 2. Website Health Check
  Each website is pinged to check if it’s online.

  🔴 3. If Website is Down:
  It verifies if a downtime record already exists.
  If not, it:
    Adds a new row in the Google Sheet with the timestamp.
    Sends notifications via:
      📧 Email
      💬 Slack
      📲 Telegram
      📞 Voice Call via Vapi

  🟢 4. If Website is Back Up:
  It fetches the matching downtime record.
  Updates the sheet with:
    ✅ Uptime timestamp
    ⏱ Total downtime duration
  Sends recovery notifications via:
    📧 Email
    💬 Slack
    📲 Telegram  
  (No phone call is made for uptime.)

  👤 Who can use it?

  This is perfect for:
  🚀 Startups
  👨‍💻 Freelance Developers
  🛠 SaaS Product Owners
  🖥 IT/DevOps Teams

  If you're looking to replace tools like UptimeRobot, Pingdom, or StatusCake, this no-code solution gives you full control, customization, and cost-efficiency.

nodes_used:
  ["n8n-nodes-base.googleSheets","n8n-nodes-base.httpRequest","n8n-nodes-base.slack","n8n-nodes-base.telegram","n8n-nodes-base.gmail","n8n-nodes-base.code"]

workflow_json:
  {"id":"Cki3H3LKIaoXKG1r","meta":{"instanceId":"fcb622cbd5234c565b9b78babeaf0ea2455df9d2aad0d1adff7c1ef99583e685","templateCredsSetupCompleted":true},"name":"Website Down Time Monitoring for n8n","tags":[],"nodes":[{"id":"89285dd4-89d7-4726-b2d5-70b919d1738a","name":"Schedule Trigger","type":"n8n-nodes-base.scheduleTrigger","position":[-1120,2425],"parameters":{"rule":{"interval":[{}]}},"typeVersion":1.2},{"id":"f624f586-07eb-4e5e-b748-9e5605e2b102","name":"Loop Over Items","type":"n8n-nodes-base.splitInBatches","position":[-680,2425],"parameters":{"options":{}},"typeVersion":3},{"id":"4bf3a7b5-62a1-402d-bf22-3222d1767a67","name":"Check website status","type":"n8n-nodes-base.httpRequest","position":[-460,1900],"parameters":{"url":"={{ $json['Website URL'] }}","options":{"timeout":5000,"response":{"response":{"fullResponse":true}}}},"typeVersion":4.2},{"id":"6f17ae5e-5451-4b78-99b1-20fa16255ead","name":"Website URLs","type":"n8n-nodes-base.googleSheets","position":[-900,2425],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":959117872,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY/edit#gid=959117872","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY/edit?usp=drivesdk","cachedResultName":"Website Moniter"}},"credentials":{"googleSheetsOAuth2Api":{"id":"AjFU8eA6fXFRo47v","name":"Google Sheets account"}},"executeOnce":false,"typeVersion":4.6},{"id":"9a429a0a-06f0-49ca-9d6a-d2bfa55a996c","name":"Get Active Down Record","type":"n8n-nodes-base.googleSheets","position":[-20,1800],"parameters":{"options":{},"filtersUI":{"values":[{"lookupValue":"={{ $('Loop Over Items').item.json['Website URL'] }}","lookupColumn":"Website URL"},{"lookupColumn":"Up Time"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY/edit#gid=0","cachedResultName":"Sheet2"},"documentId":{"__rl":true,"mode":"list","value":"1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY/edit?usp=drivesdk","cachedResultName":"Website Moniter"}},"credentials":{"googleSheetsOAuth2Api":{"id":"AjFU8eA6fXFRo47v","name":"Google Sheets account"}},"executeOnce":false,"typeVersion":4.6,"alwaysOutputData":true},{"id":"57f054ee-8f40-45a9-9da9-3befd1ac489c","name":"Update Uptime and Total Downtime","type":"n8n-nodes-base.googleSheets","position":[420,1800],"parameters":{"columns":{"value":{"Up Time":"={{ new Date().toLocaleTimeString('en-GB', { hour12: false }) }}","row_number":"={{ $json.row_number }}","Website URL":"={{ $json['Website URL'] }}","Total downtime":"={{(() => {\n  const downTimeStr = $input.first().json['Down Time'];\n\n  // Get current time in HH:MM:SS format\n  const now = new Date();\n  const upTimeStr = now.toLocaleTimeString('en-GB', { hour12: false });\n\n  function parseTime(timeStr) {\n    const [h, m, s] = timeStr.split(\":\").map(Number);\n    const date = new Date();\n    date.setHours(h, m, s, 0);\n    return date;\n  }\n\n  const downTime = parseTime(downTimeStr);\n  const upTime = parseTime(upTimeStr);\n\n  // Handle overnight scenario\n  if (upTime < downTime) {\n    upTime.setDate(upTime.getDate() + 1);\n  }\n\n  const diffMs = upTime - downTime;\n  const totalMinutes = Math.floor(diffMs / 60000);\n  const hours = Math.floor(totalMinutes / 60);\n  const minutes = totalMinutes % 60;\n  const seconds = Math.floor((diffMs % 60000) / 1000);\n\n  return `${hours}h ${minutes}m ${seconds}s`;\n})()}}"},"schema":[{"id":"Website URL","type":"string","display":true,"removed":false,"required":false,"displayName":"Website URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Down Time","type":"string","display":true,"removed":true,"required":false,"displayName":"Down Time","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Up Time","type":"string","display":true,"removed":false,"required":false,"displayName":"Up Time","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Total downtime","type":"string","display":true,"removed":false,"required":false,"displayName":"Total downtime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":false,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["row_number"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY/edit#gid=0","cachedResultName":"Sheet2"},"documentId":{"__rl":true,"mode":"list","value":"1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY/edit?usp=drivesdk","cachedResultName":"Website Moniter"}},"credentials":{"googleSheetsOAuth2Api":{"id":"AjFU8eA6fXFRo47v","name":"Google Sheets account"}},"executeOnce":false,"typeVersion":4.6,"alwaysOutputData":true},{"id":"e6575156-1a32-429a-9ee7-deef3c4f863d","name":"Find Existing Record","type":"n8n-nodes-base.code","position":[200,2200],"parameters":{"jsCode":"let hasIncompleteRecord = false;\n\nfor (const item of $input.all()) {\n  const url = item.json['Website URL']?.trim();\n  const downTime = item.json['Down Time']?.trim();\n  const upTime = item.json['Up Time']?.trim();\n  const totalDowntime = item.json['Total downtime']?.trim();\n\n  if (url && downTime && (!upTime || !totalDowntime)) {\n    hasIncompleteRecord = true;\n  }\n}\n\nreturn [\n  {\n    json: {\n      status: hasIncompleteRecord ? \"yes\" : \"no\",\n      websites: $input.first().json['Website URL']\n    }\n  }\n];\n"},"typeVersion":2},{"id":"220717dd-659a-44af-98f8-3e03aa0021ea","name":"Add Downtime Record","type":"n8n-nodes-base.googleSheets","position":[640,2200],"parameters":{"columns":{"value":{"Down Time":"={{ new Date().toLocaleTimeString('en-GB', { hour12: false }) }}","Website URL":"={{ $('Loop Over Items').item.json[\"Website URL\"] }}"},"schema":[{"id":"Website URL","type":"string","display":true,"removed":false,"required":false,"displayName":"Website URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Down Time","type":"string","display":true,"removed":false,"required":false,"displayName":"Down Time","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Up Time","type":"string","display":true,"removed":true,"required":false,"displayName":"Up Time","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Total downtime","type":"string","display":true,"removed":true,"required":false,"displayName":"Total downtime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":false,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["Website URL"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY/edit#gid=0","cachedResultName":"Sheet2"},"documentId":{"__rl":true,"mode":"list","value":"1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY/edit?usp=drivesdk","cachedResultName":"Website Moniter"}},"credentials":{"googleSheetsOAuth2Api":{"id":"AjFU8eA6fXFRo47v","name":"Google Sheets account"}},"executeOnce":false,"typeVersion":4.6},{"id":"59d163f7-771e-40e6-bf5f-e091de3233a9","name":"Notify over Phone Call","type":"n8n-nodes-base.httpRequest","position":[860,2580],"parameters":{"url":"https://api.vapi.ai/call","method":"POST","options":{},"jsonBody":"={\n  \"assistantId\": \"assistant_id\",\n  \"assistantOverrides\": {\n    \"variableValues\": {\n    \"name\":\"John\",\n    \"web_domain\":\"{{ $json['Website URL'] }}\"\n    }\n  },\n  \"customer\": {\n    \"number\": \"+919999999999\"\n  },\n  \"phoneNumberId\": \"phone_number_id\"\n}","sendBody":true,"sendHeaders":true,"specifyBody":"json","headerParameters":{"parameters":[{"name":"Authorization","value":"Bearer vapi_api_key"}]}},"typeVersion":4.2,"alwaysOutputData":true},{"id":"5345ee2f-55bf-4211-bd40-286fbf522af0","name":"Check Downtime Exists","type":"n8n-nodes-base.if","position":[420,2200],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"9e5df4d3-c9fd-4311-ae97-c06fcbcc1c97","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.status }}","rightValue":"yes"}]}},"typeVersion":2.2},{"id":"ef94a17c-ddd7-48f2-88a1-a0dd3790e20b","name":"Email Notification for Down","type":"n8n-nodes-base.gmail","position":[860,1975],"webhookId":"01059553-6361-4349-99c0-d6e467198e19","parameters":{"sendTo":"example@gmail.com","message":"=Hi there,\n\nThe Website {{ $json['Website URL'] }} is Down. Please take the required action as soon as possible.","options":{},"subject":"=Your site is down!!"},"credentials":{"gmailOAuth2":{"id":"IXi1kkbb2nCpoTSR","name":"Gmail account"}},"typeVersion":2.1},{"id":"e79a52cd-7ea4-41fc-80e3-82ac947d4d1f","name":"Slack Notification for Down","type":"n8n-nodes-base.slack","position":[860,2175],"webhookId":"379f0487-218b-4137-9a89-02c29f9ab48f","parameters":{"text":"=🚨 Alert:| Hi there, The {{ $json['Website URL'] }} website is currently down. Kindly look into this issue and take necessary action as soon as possible.  Thank you.","user":{"__rl":true,"mode":"list","value":"U08QEDH1YVB","cachedResultName":"mail"},"select":"user","otherOptions":{"includeLinkToWorkflow":false},"authentication":"oAuth2"},"credentials":{"slackOAuth2Api":{"id":"zPPPZzCjzqdYPosb","name":"Slack account 2"}},"typeVersion":2.3},{"id":"8203750f-b83b-4f7e-9982-69bf88e3ccb2","name":"Telegram Notification for Down","type":"n8n-nodes-base.telegram","position":[860,2375],"webhookId":"b76cf08e-146f-4dce-8b55-0467b6130b5c","parameters":{"text":"=🚨 Alert: Hi there, | The {{ $json['Website URL'] }} website is currently down. Kindly look into this issue and take necessary action as soon as possible.  Thank you.","chatId":"-1002286661825","additionalFields":{}},"credentials":{"telegramApi":{"id":"LXHr60rCVMuiROdo","name":"Telegram account 2"}},"typeVersion":1.2},{"id":"5a86f273-6c29-47c8-9c88-9f36bd56cfba","name":"Email Notification for Up","type":"n8n-nodes-base.gmail","position":[640,1600],"webhookId":"01059553-6361-4349-99c0-d6e467198e19","parameters":{"sendTo":"example@gmail.com","message":"=Hi there,\n\nWe're excited to announce that the {{ $('Website URLs').item.json['Website URL'] }} is now live!\nFeel free to visit and explore.","options":{},"subject":"=Site is now working fine."},"credentials":{"gmailOAuth2":{"id":"IXi1kkbb2nCpoTSR","name":"Gmail account"}},"typeVersion":2.1},{"id":"19a35cc4-9477-476b-973c-02ccbe4746a4","name":"Slack Notification for Up","type":"n8n-nodes-base.slack","position":[640,1800],"webhookId":"379f0487-218b-4137-9a89-02c29f9ab48f","parameters":{"text":"We're excited to announce that the {{ $('Website URLs').item.json['Website URL'] }} is now live! Feel free to visit and explore.","user":{"__rl":true,"mode":"list","value":"U08QEDH1YVB","cachedResultName":"mail"},"select":"user","otherOptions":{"includeLinkToWorkflow":false},"authentication":"oAuth2"},"credentials":{"slackOAuth2Api":{"id":"zPPPZzCjzqdYPosb","name":"Slack account 2"}},"typeVersion":2.3},{"id":"5465b80d-c302-4931-988e-f36ac48bcdef","name":"Telegram Notification for Up","type":"n8n-nodes-base.telegram","position":[640,2000],"webhookId":"b76cf08e-146f-4dce-8b55-0467b6130b5c","parameters":{"text":"We're excited to announce that the {{ $('Website URLs').item.json['Website URL'] }} is now live! Feel free to visit and explore.","chatId":"-1002286661825","additionalFields":{}},"credentials":{"telegramApi":{"id":"LXHr60rCVMuiROdo","name":"Telegram account 2"}},"typeVersion":1.2},{"id":"ddcd8c3d-a22e-4ae7-bf00-3677c6a9a10c","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-340,1460],"parameters":{"width":560,"height":280,"content":"### Website downtime monitoring with logging\nSample Sheet: https://docs.google.com/spreadsheets/d/1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY/edit?usp=sharing\n- Sheet 1 - Add domain list for monitoring.\n- Sheet 2 - Store all downtime logs.\n\n\nCreate new assistant in Vapi and set First message as below.\n- Hello {{name}}, I'm Website Monitoring Assistant. This is a system alert. The {{web_domain}} is currently down. Please take immediate action to investigate and resolve the issue. Thank you.\n\n\n"},"typeVersion":1},{"id":"1a4b919f-6e78-48f3-968d-0caae9fe56f4","name":"If Down Record Exist","type":"n8n-nodes-base.if","position":[200,1800],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"1337beb6-7974-45ab-9fa0-93f5ce0ee7b7","operator":{"type":"boolean","operation":"false","singleValue":true},"leftValue":"={{(() => {   const data = $json;   return Object.keys(data).length === 0; })()}}","rightValue":""}]}},"typeVersion":2.2},{"id":"c60f06ef-ab17-40d1-91b7-1ed1683c9c42","name":"If Site Up","type":"n8n-nodes-base.if","position":[-240,1900],"parameters":{"conditions":{"number":[{"value1":"={{$json[\"statusCode\"]}}","value2":400,"operation":"equal"}]}},"typeVersion":1},{"id":"08a21aa6-89c6-406b-becd-43688b793b2c","name":"Get Existing Down Records","type":"n8n-nodes-base.googleSheets","position":[-20,2200],"parameters":{"options":{},"filtersUI":{"values":[{"lookupValue":"={{ $('Loop Over Items').item.json['Website URL'] }}","lookupColumn":"Website URL"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY/edit#gid=0","cachedResultName":"Sheet2"},"documentId":{"__rl":true,"mode":"list","value":"1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1_VVpkIvpYQigw5q0KmPXUAC2aV2rk1nRQLQZ7YK2KwY/edit?usp=drivesdk","cachedResultName":"Website Moniter"}},"credentials":{"googleSheetsOAuth2Api":{"id":"AjFU8eA6fXFRo47v","name":"Google Sheets account"}},"typeVersion":4.6,"alwaysOutputData":true}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"da032169-3ed0-4c4b-a5a9-bef39dd9bf55","connections":{"If Site Up":{"main":[[{"node":"Get Active Down Record","type":"main","index":0}],[{"node":"Get Existing Down Records","type":"main","index":0}]]},"Website URLs":{"main":[[{"node":"Loop Over Items","type":"main","index":0}]]},"Loop Over Items":{"main":[[],[{"node":"Check website status","type":"main","index":0}]]},"Schedule Trigger":{"main":[[{"node":"Website URLs","type":"main","index":0}]]},"Add Downtime Record":{"main":[[{"node":"Email Notification for Down","type":"main","index":0},{"node":"Slack Notification for Down","type":"main","index":0},{"node":"Telegram Notification for Down","type":"main","index":0},{"node":"Notify over Phone Call","type":"main","index":0}]]},"Check website status":{"main":[[{"node":"If Site Up","type":"main","index":0}]]},"Find Existing Record":{"main":[[{"node":"Check Downtime Exists","type":"main","index":0}]]},"If Down Record Exist":{"main":[[{"node":"Update Uptime and Total Downtime","type":"main","index":0}],[{"node":"Loop Over Items","type":"main","index":0}]]},"Check Downtime Exists":{"main":[[{"node":"Loop Over Items","type":"main","index":0}],[{"node":"Add Downtime Record","type":"main","index":0}]]},"Get Active Down Record":{"main":[[{"node":"If Down Record Exist","type":"main","index":0}]]},"Notify over Phone Call":{"main":[[{"node":"Loop Over Items","type":"main","index":0}]]},"Get Existing Down Records":{"main":[[{"node":"Find Existing Record","type":"main","index":0}]]},"Email Notification for Down":{"main":[[]]},"Slack Notification for Down":{"main":[[]]},"Telegram Notification for Up":{"main":[[{"node":"Loop Over Items","type":"main","index":0}]]},"Telegram Notification for Down":{"main":[[]]},"Update Uptime and Total Downtime":{"main":[[{"node":"Email Notification for Up","type":"main","index":0},{"node":"Slack Notification for Up","type":"main","index":0},{"node":"Telegram Notification for Up","type":"main","index":0}]]}}}


name: Automated AI Lead Enrichment: Salesforce to Explorium for Enhanced Prospect Data
author_name: explorium
author_username: explorium
nodes_used: ["n8n-nodes-base.httpRequest","n8n-nodes-base.salesforce","n8n-nodes-base.code"]
categories: []
created_at: 2025-06-10T06:39:17.145Z
updated_at: 2025-06-10T06:39:17.145Z
url: https://n8n.io/workflows/4837
scraped_at: 2025-06-19 22:49:41
description:
  Salesforce Lead Enrichment with Explorium

  Template

  Download the following json file and import it to a new n8n workflow:

  salesforce\_Workflow.json

  Overview

  This n8n workflow monitors your Salesforce instance for new leads and automatically enriches them with missing contact information. When a lead is created, the workflow:

  Detects the new lead via Salesforce trigger
  Matches the lead against Explorium's database using name and company
  Enriches the lead with professional email addresses and phone numbers
  Updates the Salesforce lead record with the discovered contact information

  This automation ensures your sales team always has the most up-to-date contact information for new leads, improving reach rates and accelerating the sales process.

  Key Features

  Real-time Processing**: Triggers automatically when new leads are created in Salesforce
  Intelligent Matching**: Uses lead name and company to find the correct person in Explorium's database
  Contact Enrichment**: Adds professional emails, mobile phones, and office phone numbers
  Batch Processing**: Efficiently handles multiple leads to optimize API usage
  Error Handling**: Continues processing other leads even if some fail to match
  Selective Updates**: Only updates leads that successfully match in Explorium

  Prerequisites

  Before setting up this workflow, ensure you have:

  n8n instance (self-hosted or cloud)
  Salesforce account with:
     OAuth2 API access enabled
     Lead object permissions (read/write)
     API usage limits available
  Explorium API credentials (Bearer token) - Get explorium api key
  Basic understanding of Salesforce lead management

  Salesforce Requirements

  Required Lead Fields

  The workflow expects these standard Salesforce lead fields:

  FirstName - Lead's first name
  LastName - Lead's last name
  Company - Company name
  Email - Will be populated/updated by the workflow
  Phone - Will be populated/updated by the workflow
  MobilePhone - Will be populated/updated by the workflow

  API Permissions

  Your Salesforce integration user needs:

  Read access to Lead object
  Write access to Lead object fields (Email, Phone, MobilePhone)
  API enabled on the user profile
  Sufficient API calls remaining in your org limits

  Installation & Setup

  Step 1: Import the Workflow

  Copy the workflow JSON from the template
  In n8n: Navigate to Workflows → Add Workflow → Import from File
  Paste the JSON and click Import

  Step 2: Configure Salesforce OAuth2 Credentials

  Click on the Salesforce Trigger node
  Under Credentials, click Create New
  Follow the OAuth2 flow:
     Client ID: From your Salesforce Connected App
     Client Secret: From your Salesforce Connected App
     Callback URL: Copy from n8n and add to your Connected App
  Authorize the connection
  Save the credentials as "Salesforce account connection"

  Note: Use the same credentials for all Salesforce nodes in the workflow.

  Step 3: Configure Explorium API Credentials

  Click on the Match\_prospect node
  Under Credentials, click Create New (HTTP Header Auth)
  Configure the header:
     Name: Authorization
     Value: Bearer YOUR_EXPLORIUM_API_TOKEN
  Save as "Header Auth account"
  Apply the same credentials to the Explorium Enrich Contacts Information node

  Step 4: Verify Node Settings

  Salesforce Trigger:
     Trigger On: Lead Created
     Poll Time: Every minute (adjust based on your needs)

  Salesforce Get Leads:
     Operation: Get All
     Condition: CreatedDate = TODAY (fetches today's leads)
     Limit: 20 (adjust based on volume)

  Loop Over Items:
     Batch Size: 6 (optimal for API rate limits)

  Step 5: Activate the Workflow

  Save the workflow
  Toggle the Active switch to ON
  The workflow will now monitor for new leads every minute

  Detailed Node Descriptions

  Salesforce Trigger: Polls Salesforce every minute for new leads
  Get Today's Leads: Retrieves all leads created today to ensure none are missed
  Loop Over Items: Processes leads in batches of 6 for efficiency
  Match Prospect: Searches Explorium for matching person using name + company
  Filter: Checks if a valid match was found
  Extract Prospect IDs: Collects all matched prospect IDs
  Enrich Contacts: Fetches detailed contact information from Explorium
  Merge: Combines original lead data with enrichment results
  Split Out: Separates individual enriched records
  Update Lead: Updates Salesforce with new contact information

  Data Mapping

  The workflow maps Explorium data to Salesforce fields as follows:

  | Explorium Field     | Salesforce Field | Fallback Logic                    |
  | ------------------- | ---------------- | --------------------------------- |
  | emails[0].address | Email            | Falls back to professions_email |
  | mobile_phone      | MobilePhone      | Falls back to phone_numbers[1]  |
  | phone_numbers[0]  | Phone            | Falls back to mobile_phone      |

  Usage & Monitoring

  Automatic Operation

  Once activated, the workflow runs automatically:

  Checks for new leads every minute
  Processes any leads created since the last check
  Updates leads with discovered contact information
  Continues running until deactivated

  Manual Testing

  To test the workflow manually:

  Create a test lead in Salesforce
  Click "Execute Workflow" in n8n
  Monitor the execution to see each step
  Verify the lead was updated in Salesforce

  Monitoring Executions

  Track workflow performance:

  Go to Executions in n8n
  Filter by this workflow
  Review successful and failed executions
  Check logs for any errors or issues

  Troubleshooting

  Common Issues

  No leads are being processed

  Verify the workflow is activated
  Check Salesforce API limits haven't been exceeded
  Ensure new leads have FirstName, LastName, and Company populated
  Confirm OAuth connection is still valid

  Leads not matching in Explorium

  Verify company names are accurate (not abbreviations)
  Check that first and last names are properly formatted
  Some individuals may not be in Explorium's database
  Try testing with known companies/contacts

  Contact information not updating

  Check Salesforce field-level security
  Verify the integration user has edit permissions
  Ensure Email, Phone, and MobilePhone fields are writeable
  Check for validation rules blocking updates

  Authentication errors

  Salesforce: Re-authorize OAuth connection
  Explorium: Verify Bearer token is valid and not expired
  Check API quotas haven't been exceeded

  Error Handling

  The workflow includes built-in error handling:

  Failed matches don't stop other leads from processing
  Each batch is processed independently
  Failed executions are logged for review
  Partial successes are possible (some leads updated, others skipped)

  Best Practices

  Data Quality

  Ensure complete lead data: FirstName, LastName, and Company should be populated
  Use full company names: "Microsoft Corporation" matches better than "MSFT"
  Standardize data entry: Consistent formatting improves match rates

  Performance Optimization

  Adjust batch size: Lower if hitting API limits, higher for efficiency
  Modify polling frequency: Every minute for high volume, less frequent for lower volume
  Set appropriate limits: Balance between processing speed and API usage

  Compliance & Privacy

  Data permissions: Ensure you have rights to enrich lead data
  GDPR compliance: Consider privacy regulations in your region
  Data retention: Follow your organization's data policies
  Audit trail: Monitor who has access to enriched data

  Customization Options

  Extend the Enrichment

  Add more Explorium enrichment by:

  Adding firmographic data (company size, revenue)
  Including technographic information
  Appending social media profiles
  Adding job title and department verification

  Modify Trigger Conditions

  Change when enrichment occurs:

  Trigger on lead updates (not just creation)
  Add specific lead source filters
  Process only leads from certain campaigns
  Include lead score thresholds

  Add Notifications

  Enhance with alerts:

  Email sales reps when leads are enriched
  Send Slack notifications for high-value matches
  Create tasks for leads that couldn't be enriched
  Log enrichment metrics to dashboards

  API Considerations

  Salesforce Limits

  API calls: Each execution uses \~4 Salesforce API calls
  Polling frequency: Consider your daily API limit
  Batch processing: Reduces API usage vs. individual processing

  Explorium Limits

  Match API: One call per batch of leads
  Enrichment API: One call per batch of matched prospects
  Rate limits: Respect your plan's requests per minute

  Integration Architecture

  This workflow can be part of a larger lead management system:

  Lead Capture → This Workflow → Lead Scoring → Assignment
  Can trigger additional workflows based on enrichment results
  Compatible with existing Salesforce automation (Process Builder, Flows)
  Works alongside other enrichment tools

  Security Considerations

  Credentials**: Stored securely in n8n's credential system
  Data transmission**: Uses HTTPS for all API calls
  Access control**: Limit who can modify the workflow
  Audit logging**: All executions are logged with details

  Support Resources

  For assistance with:

  n8n issues**: Consult n8n documentation or community forum
  Salesforce integration**: Reference Salesforce API documentation
  Explorium API**: Contact Explorium support for API questions
  Workflow logic**: Review execution logs for debugging

workflow_json:
  {"id":"u92uqa8glb0TuCG9","meta":{"instanceId":"0a70652f43c1b29dd16c35b61a38fd31c8004f58bc7e723bf43262a797407c77","templateCredsSetupCompleted":true},"name":"Salesforce  with 2 prospect enrichments - final","tags":[],"nodes":[{"id":"70a40c85-eb5d-41b0-96ab-11ba442189c8","name":"Salesforce Trigger","type":"n8n-nodes-base.salesforceTrigger","position":[-1880,680],"parameters":{"pollTimes":{"item":[{"mode":"everyMinute"}]},"triggerOn":"leadCreated"},"credentials":{"salesforceOAuth2Api":{"id":"unhmsSbB64eNwCMO","name":"Salesforce account"}},"typeVersion":1},{"id":"b16d1538-753a-405f-884c-c05dd1076c15","name":"Update Lead","type":"n8n-nodes-base.salesforce","position":[-340,680],"parameters":{"leadId":"={{ $('Salesforce Trigger').item.json.Id}}","operation":"update","updateFields":{"city":"={{ $json.city || null }}","email":"={{ $json.professions_email || null }}","phone":"={{ $json.phone_numbers?.[0]?.phone_number || \"null\" }}\n","state":"={{ $json.region_name || '' }}","title":"={{ $json.experience?.[0]?.title?.name || null }}","company":"={{ $json.company_name || null }}","country":"={{ $json.country_name || null }}","website":"={{ $json.experience?.[0]?.company?.website || null }}","mobilePhone":"={{ $json.mobile_phone }}"}},"credentials":{"salesforceOAuth2Api":{"id":"unhmsSbB64eNwCMO","name":"Salesforce account"}},"typeVersion":1},{"id":"5417925f-919e-4c44-ba21-9249cab895eb","name":"Match_prospect","type":"n8n-nodes-base.httpRequest","position":[-1660,680],"parameters":{"url":"https://api.explorium.ai/v1/prospects/match","method":"POST","options":{},"jsonBody":"={\n  \"prospects_to_match\": [\n    {\n      \"full_name\": \"{{ $('Salesforce Trigger').item.json.FirstName }} {{ $('Salesforce Trigger').item.json.LastName }}\",\n      \"company_name\": \"{{ $('Salesforce Trigger').item.json.Company }}\"\n    }\n  ]\n}","sendBody":true,"jsonHeaders":"{\n  \"Content-Type\": \"application/json\",\n  \"Accept\": \"application/json\"\n}","sendHeaders":true,"specifyBody":"json","authentication":"genericCredentialType","specifyHeaders":"json","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"85mkGmNNdK1951hF","name":"Header Auth Connection"}},"typeVersion":4.2},{"id":"360ca1d3-c1e6-46f4-b190-ddf76ed8847b","name":"Extract Prospect IDs from Matched Results","type":"n8n-nodes-base.code","position":[-1220,680],"parameters":{"jsCode":"const allItems = $input.all();\nconst prospectIds = allItems.map(item => \n  item.json.matched_prospects.map(prospect => prospect.prospect_id)\n).flat();\n\nreturn [{\n  json: {\n    prospect_ids: prospectIds\n  }\n}];"},"typeVersion":2},{"id":"aa419a45-dae1-47b0-8030-5fe0e193f804","name":"Explorium Enrich Contacts Information","type":"n8n-nodes-base.httpRequest","position":[-1000,580],"parameters":{"url":"https://api.explorium.ai/v1/prospects/contacts_information/bulk_enrich","method":"POST","options":{},"jsonBody":"={{ { \"prospect_ids\": $json.prospect_ids } }}","sendBody":true,"jsonHeaders":"{\n  \"Content-Type\": \"application/json\",\n  \"Accept\": \"application/json\"\n}","sendHeaders":true,"specifyBody":"=json","authentication":"genericCredentialType","bodyParameters":{"parameters":[{}]},"specifyHeaders":"json","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"85mkGmNNdK1951hF","name":"Header Auth Connection"}},"typeVersion":4.2},{"id":"91bfa198-cecf-406f-94d8-1433a75e0ada","name":"Merge","type":"n8n-nodes-base.merge","position":[-780,680],"parameters":{"mode":"combine","options":{},"fieldsToMatchString":"data[0].prospect_id"},"typeVersion":3.1},{"id":"7d7866ec-8839-48c4-9dd7-239844dfb207","name":"Filter non-matched","type":"n8n-nodes-base.filter","position":[-1440,680],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"6896e951-8d66-41b1-87a5-a96d2e049675","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{ $json.matched_prospects.some(prospect => prospect.prospect_id !== null).toBoolean() }}","rightValue":"null"}]}},"typeVersion":2.2},{"id":"b67d5f83-2ba9-4c78-84ff-0a94382788f8","name":"Code - flatten","type":"n8n-nodes-base.code","position":[-560,680],"parameters":{"jsCode":"return $input.all().map(item => \n    item.json.data.map(prospect => ({\n      prospect_id: prospect.prospect_id,\n      ...prospect.data\n    }))\n  ).flat()"},"typeVersion":2},{"id":"96abf132-7d7e-4e91-89da-5f0b373385a9","name":"Explorium Enrich Profiles","type":"n8n-nodes-base.httpRequest","position":[-1000,780],"parameters":{"url":"https://api.explorium.ai/v1/prospects/profiles/bulk_enrich","method":"POST","options":{},"jsonBody":"={{ { \"prospect_ids\": $json.prospect_ids } }}","sendBody":true,"jsonHeaders":"{\n  \"Content-Type\": \"application/json\",\n  \"Accept\": \"application/json\"\n}","sendHeaders":true,"specifyBody":"=json","authentication":"genericCredentialType","bodyParameters":{"parameters":[{}]},"specifyHeaders":"json","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"85mkGmNNdK1951hF","name":"Header Auth Connection"}},"typeVersion":4.2},{"id":"6c17ea6e-165f-407a-b4c9-8731d44243f8","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-2760,480],"parameters":{"width":760,"height":2720,"content":"# Automatically enrich leads in Salesforce using Explorium MCP\n\nThis n8n workflow streamlines the process of enriching lead information by automatically detecting new leads created in Salesforce, processing them through Explorium's AI-powered tools, and updating the same leads back in Salesforce with enhanced prospect details.\n\n## Credentials Required\n\nTo use this workflow, set up the following credentials in your n8n environment:\n\n### Salesforce\n- **Type**: OAuth2 or Username/Password\n- **Used for**: triggering on new leads, updating lead records\n\n### Explorium API\n- **Type**: Generic Header Auth\n- **Header**: Authorization\n- **Value**: Bearer YOUR_API_KEY\n\nGo to Settings → Credentials, create these two credentials, and assign them in the respective nodes before running the workflow.\n\n## Workflow Overview\n\n### Node 1: Salesforce Trigger\nThis node listens for real-time events from the connected Salesforce account, specifically monitoring for new lead creation events.\n\n- **Event**: leadCreated\n- **Trigger Type**: Real-time webhook\n\nOnce triggered, the node passes metadata about the newly created lead to the next step in the flow.\n\n### Node 2: Match_prospect\nThis node sends the lead's data to Explorium's AI-powered prospect matching API in real time.\n\n- **Method**: POST\n- **Endpoint**: https://api.explorium.ai/v1/prospects/match\n- **Authentication**: Generic Header Auth (using a configured credential)\n- **Headers**: Content-Type: application/json\n\nThe request body is dynamically built from lead data, typically including: full_name, company_name, email, phone_number, linkedin. These fields are matched against Explorium's intelligence graph to return enriched or validated profiles.\n\n**Response Output**: total_matches, matched_prospects, and a prospect_id. Each response is used downstream to enrich and update lead information.\n\n### Node 3: Filter non-matched\nThis node filters the output from the Match_prospect step to ensure that only valid, matched results continue in the flow. Only records that contain at least one matched prospect with a non-null prospect_id are passed forward.\n\n**Filter Logic**: Keeps only leads that have successful prospect matches from Explorium\n\n### Node 4: Extract Prospect IDs from Matched Results\nThis node extracts all valid prospect_id values from previously matched prospects and compiles them into a flat array. It loops over all matched items, extracts each prospect_id from the matched_prospects array and returns a single object with an array of all prospect_ids.\n\n### Node 5: Explorium Enrich Contacts Information\nThis node performs bulk enrichment of contacts by querying Explorium with a list of matched prospect_ids.\n\n**Node Configuration:**\n- **Method**: POST\n- **Endpoint**: https://api.explorium.ai/v1/prospects/contacts_information/bulk_enrich\n- **Authentication**: Header Auth (using saved credentials)\n- **Headers**: \"Content-Type\": \"application/json\", \"Accept\": \"application/json\"\n\nReturns enriched contact information, such as:\n- **emails**: professional/personal email addresses\n- **phone_numbers**: mobile and work numbers\n- **professions_email**, **professional_email_status**, **mobile_phone**\n\n### Node 6: Explorium Enrich Profiles\nThis additional enrichment node provides supplementary contact data enhancement, running in parallel with the primary enrichment process to maximize data collection from different Explorium endpoints.\n\n### Node 7: Merge\nThis node combines multiple data streams from the parallel enrichment processes into a single output, allowing you to consolidate data from different Explorium enrichment endpoints. The \"combine\" setting indicates it will merge the incoming data streams rather than overwriting them.\n\n### Node 8: Code - flatten\nThis custom code node processes and transforms the merged enrichment data before updating the Salesforce lead. It can be used to:\n- Flatten nested data structures from Explorium responses\n- Format data according to Salesforce field requirements\n- Apply business logic or data validation\n- Map Explorium fields to Salesforce lead properties\n- Handle data type conversions and null values\n\n### Node 9: Update Lead\nThis final node updates the original lead in Salesforce using the enriched data returned by Explorium.\n\n- **Credential**: Salesforce OAuth2 or Username/Password\n- **Resource**: Lead\n- **Operation**: Update Lead\n\nThe node updates the existing lead record with enriched information including additional contact details, professional data, and enhanced company information obtained through the Explorium enrichment process.\n\n## Workflow Flow Summary\n\n1. **Trigger**: Salesforce webhook triggers on new lead creation\n2. **Match**: Find prospect matches using Explorium based on lead data\n3. **Filter**: Keep only successfully matched prospects\n4. **Extract**: Compile prospect IDs for bulk enrichment\n5. **Enrich**: Parallel enrichment of contact information through multiple Explorium endpoints\n6. **Merge**: Combine enrichment results into unified data\n7. **Transform**: Flatten and prepare data for Salesforce update (Code node)\n8. **Update**: Update the original lead record in Salesforce with enriched data\n\nThis workflow ensures comprehensive lead enrichment while maintaining data quality and providing seamless integration within your Salesforce environment. The parallel enrichment structure maximizes data collection efficiency, and the filtering ensures only high-quality matches are processed, resulting in enhanced lead records with valuable prospect intelligence."},"typeVersion":1}],"active":false,"pinData":{"Salesforce Trigger":[{"json":{"Id":"00QQJ00000I7no12AB","City":null,"Email":"vincent.marinelli@flushingsavings.com","Status":"New","Street":null,"Company":"flushingsavings","LastName":"marinelli","FirstName":"vincent","PostalCode":null,"attributes":{"url":"/services/data/v59.0/sobjects/Lead/00QQJ00000I7no12AB","type":"Lead"}}}]},"settings":{"executionOrder":"v1"},"versionId":"c8a79ca0-36ce-443f-b6fc-21bfa6ade38c","connections":{"Merge":{"main":[[{"node":"Code - flatten","type":"main","index":0}]]},"Update Lead":{"main":[[]]},"Code - flatten":{"main":[[{"node":"Update Lead","type":"main","index":0}]]},"Match_prospect":{"main":[[{"node":"Filter non-matched","type":"main","index":0}]]},"Filter non-matched":{"main":[[{"node":"Extract Prospect IDs from Matched Results","type":"main","index":0}]]},"Salesforce Trigger":{"main":[[{"node":"Match_prospect","type":"main","index":0}]]},"Explorium Enrich Profiles":{"main":[[{"node":"Merge","type":"main","index":1}]]},"Explorium Enrich Contacts Information":{"main":[[{"node":"Merge","type":"main","index":0}]]},"Extract Prospect IDs from Matched Results":{"main":[[{"node":"Explorium Enrich Contacts Information","type":"main","index":0},{"node":"Explorium Enrich Profiles","type":"main","index":0}]]}}}


name: WhatsApp Group Chat with Your Vector Database — No Facebook Business Required
author_name: Cecilia
author_username: cecilia
categories: []
created_at: 2025-06-10T06:40:06.825Z
updated_at: 2025-06-10T06:40:06.825Z
url: https://n8n.io/workflows/4838
scraped_at: 2025-06-19 22:49:06
description:
  Enable smart, real-time answers in your WhatsApp groups using a custom webhook, Pinecone vector database, and no Facebook Business setup.

  &gt; 🟡 Note: This template uses a custom WhatsApp webhook. It does not use the official WhatsApp Business API.  

  👥 Who is this for?

  This workflow is designed for individuals and teams who want to enable smart WhatsApp group automation — without going through Meta’s official WhatsApp Business API. Ideal for small businesses, internal teams, communities, and personal power users.

  ❓ What problem is this solving?

  Setting up WhatsApp bots with intelligent responses often requires approval from Meta and a verified business account. This workflow removes those barriers by using a self-hosted webhook to handle incoming messages and respond using a document-trained AI via Pinecone.

  ⚙️ What this workflow does

  Connects a regular WhatsApp number to a custom webhook  
  Adds the bot to any group chat (it stays silent unless mentioned)  
  Indexes documents from Google Drive into Pinecone  
  Responds with intelligent, context-aware answers from your custom knowledge base  
  Auto-updates its knowledge every minute as the document changes  

  🛠️ Setup

  Step 1: Connect Google Drive

  Set up your Google Drive credentials in n8n

  Step 2: Configure Pinecone

  Create an index in Pinecone  
     Dimension: 1536  
  Select this index in both Pinecone nodes  
  Click Test Workflow to ingest your document into Pinecone  

  Step 3: Get Access to the WhatsApp Webhook

  Fill out this form to request access  
  You’ll receive a WhatsApp confirmation for linking  

  Step 4: Test WhatsApp Integration

  ✅ One-on-one test: Send a message from another number  
  👥 Group test: Add the bot to a group; it will only respond when tagged  

  🧩 How to customize this workflow

  Modify the system prompt inside the AI agent node to control tone and behavior  
  Update the connected Google Doc to match your specific domain (e.g. FAQs, SOPs, product manuals)  
  Adjust the Pinecone sync frequency if you want updates more or less often  

  📚 Use cases

  Customer Support**: Instant, intelligent replies in WhatsApp without live agents  
  Team Knowledge Bot**: Tag the bot for quick access to SOPs and internal docs  
  Community Groups**: Automate common questions while keeping noise low  
  Personal AI Assistant**: A WhatsApp chatbot trained on your notes and files  

  📝 Sticky Note Suggestion

   💬 What this template does:  
  &gt; Enables an AI bot in your WhatsApp group that answers questions based on a Google Doc you provide. It uses a custom webhook, Google Drive, and Pinecone.  

  🔧 Requirements:  
  &gt;  Google Drive account  
  &gt;  Pinecone account with an index (dimension 1536)  
  &gt; Access to the custom WhatsApp webhook (see setup steps)  

nodes_used:
  ["n8n-nodes-base.googleDrive","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.embeddingsOpenAi","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryBufferWindow","@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter","@n8n/n8n-nodes-langchain.vectorStorePinecone","@n8n/n8n-nodes-langchain.documentDefaultDataLoader"]

workflow_json:
  {"meta":{"instanceId":"e42ff03bc515cd7f9edc081a89072ca1985132e0d4a1cdabe6c26855a252768f","templateId":"1960","templateCredsSetupCompleted":true},"nodes":[{"id":"1f2bb917-6d65-4cfa-9474-fc3b19a8c3bd","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[60,200],"parameters":{"color":7,"width":1218,"height":627,"content":"## Load Information from a Google Drive File into a Pinecone Vector Database\nFetch the file from Google Drive, split it into chunks, and insert the chunks into a Pinecone index."},"typeVersion":1},{"id":"ab577f4d-8906-4e0c-bc62-e8a4b2610551","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-500,260],"parameters":{"width":480,"height":145,"content":"## Step 1: Connect Your Google Drive  \nFollow the instructions in the official n8n docs to set up your Google Drive credentials: \n👉 [Google Drive Credentials Guide](https://docs.n8n.io/integrations/builtin/credentials/google/)"},"typeVersion":1},{"id":"742beb54-8b89-49a3-afe5-fd7e73b37044","name":"Default Data Loader","type":"@n8n/n8n-nodes-langchain.documentDefaultDataLoader","position":[720,500],"parameters":{"options":{},"dataType":"binary"},"typeVersion":1},{"id":"f75e31e9-f752-45d1-bc44-75097ec85ce6","name":"Recursive Character Text Splitter","type":"@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter","position":[800,620],"parameters":{"options":{},"chunkSize":3000,"chunkOverlap":200},"typeVersion":1},{"id":"bac883c8-4c1f-466b-b20f-d0fdf6acfc42","name":"Embeddings OpenAI","type":"@n8n/n8n-nodes-langchain.embeddingsOpenAi","position":[600,500],"parameters":{"options":{}},"credentials":{"openAiApi":{"id":"wsxLB7on237QOp5h","name":"Open AI credentials"}},"typeVersion":1.2},{"id":"430f667b-9d23-4bb9-b87d-5d9e8ae84df3","name":"Simple Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[1500,1180],"parameters":{"sessionKey":"={{ $json.fromNumber }}","sessionIdType":"customKey","contextWindowLength":20},"typeVersion":1.3},{"id":"1a2e6717-a220-4f39-8ae9-1921cbff5715","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[1260,1200],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"wsxLB7on237QOp5h","name":"Open AI credentials"}},"typeVersion":1.2},{"id":"7e03e08d-0b61-4054-aa14-8f839d7f0565","name":"Question & Answer","type":"@n8n/n8n-nodes-langchain.agent","position":[1380,960],"parameters":{"text":"=Sender Name: {{ $json.fromName }}\nMessage: {{ $json.textBody }}","options":{"systemMessage":"=Agent Name: Van\nIdentity:\nYou are a friendly AI agent named Van. You are professional digital sales agent for GrayBox, a company specializing in Structural Insulated Panels (SIP) construction. Van immediately identifies as a digital assistant and exists to serve prospective and current customers of GrayBox with accurate, helpful, and engaging information that supports decision-making and promotes trust.\n\nYour Personality & Style\nTone: Clear, concise, professional—but always friendly and approachable. Talk in first person representing the company.\n\n\nIf user send link don't mention that you cannot read the link.  Explain who you are, and ask questions to engage the conversation..  Your goal is to sell our solution.  \n\nResponse Style:\n\n\nGreet, answer directly, then offer further help.\nAddress people by their names\n\n\n\nAvoid fluff and unnecessary formalities (unless it's the first message).\n\n\nMaintain consistent use of brand tone: Speed, Quality, Efficiency, Value.\n\n\nBrand Voice Keywords: Speed, Energy Efficiency, Durability, Mold-Free, Earthquake-Resistant, Friendly, Human.\n\n\n\n🔍 Scope of the Agent (What Van Can Do)\nAnswer questions about pricing, materials, SIP benefits, timeline, logistics, and project experience.\n\n\nExplain how GrayBox SIP construction works (in simple, non-technical language).\n\n\nShare relevant visual or catalog links.\n\n\nGuide users to:\n\n\nSchedule a 15-min discovery call: https://calendar.app.google/gJYWhw3LCJBPywGW6\n\n\nVisit projects like Nuanu City or Luna Beach Club.\n\n\nSubmit project materials via form: https://forms.gle/5AddUQbqveFPsTDQ9\nView portfolio: https://graybox.site/graybox-0-0 \n\n🧠 Core Behaviors & Instructions\nAlways say cost starts at 3 million IDR/m² for core and shell.\n\n\nPromote:\n\n\n1-month build time (from materials delivery).\n\n\nCost-effectiveness vs. traditional methods (20–30% cheaper, 4x faster).\n\n\nEnergy savings and safety (mold-free, earthquake-resistant).\n\n\nWhen users upload a file/image: respond with a friendly message and prompt them to fill the quotation form.\n\n\nIf asked about pictures, share: https://graybox.site/graybox-0-0\n\n\nFor meetings or calls: Share this link → https://calendar.app.google/rDzpGdMb3WmGsLFz6\n\n\nFor human contact or visit coordination: Provide Andrea's WhatsApp: +1 650 866 5016\n\n\nIf user says “OK, I’ll visit,” connect directly to Andrea.\n\n\n\n🌍 Contact & Location\nOffice: Uluwatu, Bali – https://maps.app.goo.gl/nT7VDTtLQYSztN7s9\nFactory: Lombok\n\n\nWhatsApp (Andrea): +1 650 866 5016 (only if meeting/human contact requested)\n\n🚀 First-Time Message (Greeting Script)\nDiscover GrayBox: Your dream home starts here!\n We deliver core and shell construction in under a month for developers, builders, and DIY home enthusiasts. Save time and money while enjoying a mold-free, energy-efficient, and earthquake-resistant home. All for just 3 million IDR per m²!\n Build smarter with GrayBox today. \n\nNEVER MAKEUP INFORMATION. \nUSE  {{ $json.context }} TO ANSWER QUESTIONS"},"promptType":"define"},"typeVersion":1.8},{"id":"56d150ba-9b98-4dbb-9f74-5379344d2257","name":"Respond to Whatsapp Webhook","type":"n8n-nodes-base.respondToWebhook","position":[1720,960],"parameters":{"options":{}},"typeVersion":1.2},{"id":"5d1d4427-bdab-49ef-acbc-084a2d69632f","name":"Prepare chunks","type":"n8n-nodes-base.code","position":[1200,960],"parameters":{"jsCode":"let out = \"\"\nfor (const i in $input.all()) {\n  let itemText = \"--- CHUNK \" + i + \" ---\\n\"\n  itemText += $input.all()[i].json.document.pageContent + \"\\n\"\n  itemText += \"\\n\"\n  out += itemText\n}\n\nreturn {\n  'context': out,\n  'textBody': $('Listen to Whatsapp webhook').first().json.body.textBody,\n  'fromNumber': $('Listen to Whatsapp webhook').first().json.body.fromNumber,\n  'fromName': $('Listen to Whatsapp webhook').first().json.body.fromName\n};"},"typeVersion":2},{"id":"eba8eaca-915f-4257-901e-c6f56ddf8f0b","name":"Get top chunks matching query","type":"@n8n/n8n-nodes-langchain.vectorStorePinecone","position":[840,960],"parameters":{"mode":"load","topK":"={{ $json.chunks }}","prompt":"={{ $json.body.textBody }}","options":{},"pineconeIndex":{"__rl":true,"mode":"list","value":"3vansales","cachedResultName":"3vansales"}},"credentials":{"pineconeApi":{"id":"2ZUBIWHNyYqKmASZ","name":"PineconeApi account 2"}},"typeVersion":1},{"id":"afb0bb4f-8370-4a7a-be3c-8449f5b890d5","name":"Set max chunks to send to model","type":"n8n-nodes-base.set","position":[620,960],"parameters":{"options":{},"assignments":{"assignments":[{"id":"33f4addf-72f3-4618-a6ba-5b762257d723","name":"chunks","type":"number","value":4}]},"includeOtherFields":true},"typeVersion":3.4},{"id":"d9aa944d-594f-49ad-a40e-123aa42621e3","name":"Embeddings OpenAI2","type":"@n8n/n8n-nodes-langchain.embeddingsOpenAi","position":[840,1180],"parameters":{"options":{}},"credentials":{"openAiApi":{"id":"wsxLB7on237QOp5h","name":"Open AI credentials"}},"typeVersion":1.2},{"id":"15ff0895-9bb2-47d3-92fb-d0d8d1f4a981","name":"Check for individual or group messages","type":"n8n-nodes-base.if","position":[340,980],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"5a946369-3f38-4dcb-b5d9-3d24024d08b0","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.body.threadType }}","rightValue":"individual"}]}},"typeVersion":2.2},{"id":"32df5bff-1b09-4f1c-9344-7d9ae748d917","name":"Listen to Whatsapp webhook","type":"n8n-nodes-base.webhook","position":[120,980],"webhookId":"d1629cd7-6e05-413a-bac0-3c435d4e43b9","parameters":{"path":"d1629cd7-6e05-413a-bac0-3c435d4e43b9","options":{},"httpMethod":"POST","responseMode":"responseNode"},"typeVersion":2},{"id":"8b493fb6-8013-453f-8aa5-1ee9c9d06cd9","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[60,860],"parameters":{"color":7,"width":2034,"height":627,"content":"### Chat with Your Vector Database Using a Custom WhatsApp Webhook (with Group Support)\nThis workflow takes incoming WhatsApp messages, embeds the content, retrieves relevant chunks from your vector store, and passes them to the model to generate a response."},"typeVersion":1},{"id":"d97920ad-6b36-4981-8b9d-9d470b5c769a","name":"Download the file from Google Drive","type":"n8n-nodes-base.googleDrive","position":[360,280],"parameters":{"fileId":{"__rl":true,"mode":"id","value":"={{ $json.id }}"},"options":{},"operation":"download","authentication":"serviceAccount"},"credentials":{"googleApi":{"id":"10HrAmRHIIsSrT6B","name":"Google Drive account"}},"typeVersion":3},{"id":"0a6f8b88-9c62-4e3e-82cb-a7028bdcac45","name":"Index Pinecone Vector Store","type":"@n8n/n8n-nodes-langchain.vectorStorePinecone","position":[620,280],"parameters":{"mode":"insert","options":{"clearNamespace":true},"pineconeIndex":{"__rl":true,"mode":"list","value":"3vansales","cachedResultName":"3vansales"}},"credentials":{"pineconeApi":{"id":"2ZUBIWHNyYqKmASZ","name":"PineconeApi account 2"}},"typeVersion":1},{"id":"34f220a8-12d7-480f-9954-11d777359d27","name":"Every minute check if file is updated","type":"n8n-nodes-base.googleDriveTrigger","position":[140,280],"parameters":{"pollTimes":{"item":[{"mode":"everyMinute"}]},"triggerOn":"specificFile","fileToWatch":{"__rl":true,"mode":"list","value":"1-AZrzOeeZFATUsY-xGD0m_oYkq4ekiSHn3e8Aof9pyU","cachedResultUrl":"https://docs.google.com/document/d/1-AZrzOeeZFATUsY-xGD0m_oYkq4ekiSHn3e8Aof9pyU/edit?usp=drivesdk","cachedResultName":"Knowladge Base FlatPack"},"authentication":"serviceAccount"},"credentials":{"googleApi":{"id":"10HrAmRHIIsSrT6B","name":"Google Drive account"}},"typeVersion":1},{"id":"f9016922-f6a4-417a-8586-bf0647f1e17b","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[-500,440],"parameters":{"width":480,"height":325,"content":"## Step 2: Set Up Your Pinecone Vector Database \n1. Log in to your Pinecone account and create an index: \n🚨 Dimensions: 1536\n2. In the workflow, make sure to select this index in **both Pinecone nodes**.\n3. Click \"Test Workflow\" to load your data into the vector database.\n4. Modify the connected document to fit your use case.\n\n**Note:** Once the bot is live, the vector database updates automatically every minute when changes are made. You can customize this update frequency if needed."},"typeVersion":1},{"id":"638760a3-51da-4b88-ace5-73e67e6e6e98","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-500,800],"parameters":{"color":2,"width":480,"height":205,"content":"## Step 3: Request Access to the Custom WhatsApp Webhook\n1. Fill out this form to request access: \n👉 [Request Access](https://docs.google.com/forms/d/e/1FAIpQLSd-bW5tSJu_rRvJ4NmFrxXSAwaNbO7MbGJtUIS-mBA23B7BWQ/viewform?usp=dialog)\n2. You’ll receive a confirmation message on WhatsApp to verify your connection.\n3. Customize the **AI agent's system prompt** to match your use case."},"typeVersion":1},{"id":"a9092d34-7406-4d7e-8fe4-ce392aae9c5a","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-500,1040],"parameters":{"color":2,"width":480,"height":345,"content":"## Step 4: Test the WhatsApp Integration\n#### One-on-One Testing\n1. Use a different WhatsApp number to send a message to the connected number.\n2. You should receive a reply from the AI based on:\n  ✅ Your system prompt\n  ✅ The content in your vector database\n#### Group Testing\n1. Add the bot to a WhatsApp group. \n2. The bot will only reply when tagged or addressed directly, to avoid responding to every message in the group"},"typeVersion":1},{"id":"8b338d65-cd79-41d5-b4c4-e76534d8b19c","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-1160,260],"parameters":{"width":480,"height":645,"content":"## 🔑 Key Benefits\n#### 1. No Meta Account Needed\n👉 Works with regular WhatsApp numbers — no Facebook Business setup or official API required.\n\n#### 2. Group Chat Support\n👉 Add the bot to any group. It only replies when tagged to avoid cluttering conversations.\n\n#### 3. Custom AI Responses\n👉 Connect your own documents (via Google Drive + Pinecone) to deliver context-aware replies.\n\n#### 4. Auto-Syncing Knowledge Base\n👉 Updates every minute when your source document changes — always fresh, always relevant.\n\n#### Use cases are endless\n✅ Customer support\n✅ Internal team assistant\n✅ Community group bot\n✅ Personal knowledge brain\n\nAnd so on "},"typeVersion":1}],"pinData":{},"connections":{"Simple Memory":{"ai_memory":[[{"node":"Question & Answer","type":"ai_memory","index":0}]]},"Prepare chunks":{"main":[[{"node":"Question & Answer","type":"main","index":0}]]},"Embeddings OpenAI":{"ai_embedding":[[{"node":"Index Pinecone Vector Store","type":"ai_embedding","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Question & Answer","type":"ai_languageModel","index":0}]]},"Question & Answer":{"main":[[{"node":"Respond to Whatsapp Webhook","type":"main","index":0}]]},"Embeddings OpenAI2":{"ai_embedding":[[{"node":"Get top chunks matching query","type":"ai_embedding","index":0}]]},"Default Data Loader":{"ai_document":[[{"node":"Index Pinecone Vector Store","type":"ai_document","index":0}]]},"Listen to Whatsapp webhook":{"main":[[{"node":"Check for individual or group messages","type":"main","index":0}]]},"Get top chunks matching query":{"main":[[{"node":"Prepare chunks","type":"main","index":0}]]},"Set max chunks to send to model":{"main":[[{"node":"Get top chunks matching query","type":"main","index":0}]]},"Recursive Character Text Splitter":{"ai_textSplitter":[[{"node":"Default Data Loader","type":"ai_textSplitter","index":0}]]},"Download the file from Google Drive":{"main":[[{"node":"Index Pinecone Vector Store","type":"main","index":0}]]},"Every minute check if file is updated":{"main":[[{"node":"Download the file from Google Drive","type":"main","index":0}]]},"Check for individual or group messages":{"main":[[{"node":"Set max chunks to send to model","type":"main","index":0}]]}}}


name: Automate Contact Enrichment from HubSpot to Salesforce using Explorium.ai
author_name: explorium
author_username: explorium
categories: []
created_at: 2025-06-10T06:40:34.915Z
updated_at: 2025-06-10T06:40:34.915Z
url: https://n8n.io/workflows/4839
scraped_at: 2025-06-19 22:49:52
description:
  HubSpot Contact Enrichment with Explorium

  Template

  Download the following json file and import it to a new n8n workflow:

  hubspot\_flow.json

  Overview

  This n8n workflow monitors your HubSpot instance for newly created contacts and automatically enriches them with additional contact information. When a contact is created, the workflow:

  Detects the new contact via HubSpot webhook trigger
  Retrieves recent contact details from HubSpot
  Matches the contact against Explorium's database using name, company, and email
  Enriches the contact with professional emails and phone numbers
  Updates the HubSpot contact record with discovered information

  This automation ensures your sales and marketing teams have complete contact information, improving outreach success rates and data quality.

  Key Features

  Real-time Webhook Trigger**: Instantly processes new contacts as they're created
  Intelligent Matching**: Uses multiple data points (name, company, email) for accurate matching
  Comprehensive Enrichment**: Adds both professional and work emails, plus phone numbers
  Batch Processing**: Efficiently handles multiple contacts to optimize API usage
  Smart Data Mapping**: Intelligently maps multiple emails and phone numbers
  Profile Enrichment**: Optional additional enrichment for deeper contact insights
  Error Resilience**: Continues processing other contacts if some fail to match

  Prerequisites

  Before setting up this workflow, ensure you have:

  n8n instance (self-hosted or cloud)
  HubSpot account with:
     Developer API access (for webhooks)
     Private App or OAuth2 app created
     Contact object permissions (read/write)
  Explorium API credentials (Bearer token) - Get explorium api key
  Understanding of HubSpot contact properties

  HubSpot Requirements

  Required Contact Properties

  The workflow uses these HubSpot contact properties:

  firstname - Contact's first name
  lastname - Contact's last name
  company - Associated company name
  email - Primary email (read and updated)
  work_email - Work email (updated by workflow)
  phone - Phone number (updated by workflow)

  API Access Setup

  Create a Private App in HubSpot:
     Navigate to Settings → Integrations → Private Apps
     Create new app with Contact read/write scopes
     Copy the Access Token

  Set up Webhooks (for Developer API):
     Create app in HubSpot Developers portal
     Configure webhook for contact.creation events
     Note the App ID and Developer API Key

  Custom Properties (Optional)

  Consider creating custom properties for:

  Multiple email addresses
  Mobile vs. office phone numbers
  Data enrichment timestamps
  Match confidence scores

  Installation & Setup

  Step 1: Import the Workflow

  Copy the workflow JSON from the template
  In n8n: Navigate to Workflows → Add Workflow → Import from File
  Paste the JSON and click Import

  Step 2: Configure HubSpot Developer API (Webhook)

  Click on the HubSpot Trigger node
  Under Credentials, click Create New
  Enter your HubSpot Developer credentials:
     App ID: From your HubSpot app
     Developer API Key: From your developer account
     Client Secret: From your app settings
  Save as "HubSpot Developer account"

  Step 3: Configure HubSpot App Token

  Click on the HubSpot Recently Created node
  Under Credentials, click Create New (App Token)
  Enter your Private App access token
  Save as "HubSpot App Token account"
  Apply the same credentials to the Update HubSpot node

  Step 4: Configure Explorium API Credentials

  Click on the Explorium Match Prospects node
  Under Credentials, click Create New (HTTP Header Auth)
  Configure the authentication:
     Name: Authorization
     Value: Bearer YOUR_EXPLORIUM_API_TOKEN
  Save as "Header Auth Connection"
  Apply to all Explorium nodes:
     Explorium Enrich Contacts Information
     Explorium Enrich Profiles

  Step 5: Configure Webhook Subscription

  In HubSpot Developers portal:
     Go to your app's webhook settings
     Add subscription for contact.creation events
     Set the target URL from the HubSpot Trigger node
     Activate the subscription

  Step 6: Activate the Workflow

  Save the workflow
  Toggle the Active switch to ON
  The webhook is now listening for new contacts

  Node Descriptions

  HubSpot Trigger: Webhook that fires when new contacts are created
  HubSpot Recently Created: Fetches details of recently created contacts
  Loop Over Items: Processes contacts in batches of 6
  Explorium Match Prospects: Finds matching person in Explorium database
  Filter: Validates successful matches
  Extract Prospect IDs: Collects matched prospect identifiers
  Enrich Contacts Information: Fetches emails and phone numbers
  Enrich Profiles: Gets additional profile data (optional)
  Merge: Combines all enrichment results
  Split Out: Separates individual enriched records
  Update HubSpot: Updates contact with new information

  Data Mapping Logic

  The workflow maps Explorium data to HubSpot properties:

  | Explorium Data                 | HubSpot Property   | Notes                         |
  | ------------------------------ | ------------------ | ----------------------------- |
  | professions_email            | email            | Primary professional email    |
  | emails[].address             | work_email       | All email addresses joined    |
  | phone_numbers[].phone_number | phone            | All phones joined with commas |
  | mobile_phone                 | phone (fallback) | Used if no other phones found |

  Data Processing

  The workflow handles complex data scenarios:

  Multiple emails**: Joins all discovered emails with commas
  Phone numbers**: Combines all phone numbers into a single field
  Missing data**: Uses "null" as placeholder for empty fields
  Name parsing**: Cleans sample data and special characters

  Usage & Operation

  Automatic Processing

  Once activated:

  Every new contact triggers the webhook immediately
  Contact is enriched within seconds
  HubSpot record is updated automatically
  Process repeats for each new contact

  Manual Testing

  To test the workflow:

  Use the pinned test data in the HubSpot Trigger node, or
  Create a test contact in HubSpot
  Monitor the execution in n8n
  Verify the contact was updated in HubSpot

  Monitoring Performance

  Track workflow health:

  Go to Executions in n8n
  Filter by this workflow
  Monitor success rates
  Review any failed executions
  Check webhook delivery in HubSpot

  Troubleshooting

  Common Issues

  Webhook not triggering

  Verify webhook subscription is active in HubSpot
  Check the webhook URL is correct and accessible
  Ensure workflow is activated in n8n
  Test webhook delivery in HubSpot developers portal

  Contacts not matching

  Verify contact has firstname, lastname, and company
  Check for typos or abbreviations in company names
  Some individuals may not be in Explorium's database
  Email matching improves accuracy significantly

  Updates failing in HubSpot

  Check API token has contact write permissions
  Verify property names exist in HubSpot
  Ensure rate limits haven't been exceeded
  Check for validation rules on properties

  Missing enrichment data

  Not all prospects have all data types
  Phone numbers may be less available than emails
  Profile enrichment is optional and may not always return data

  Error Handling

  Built-in error resilience:

  Failed matches don't block other contacts
  Each batch processes independently
  Partial enrichment is possible
  All errors are logged for review

  Debugging Tips

  Check webhook logs: HubSpot shows delivery attempts
  Review executions: n8n logs show detailed error messages
  Test with pinned data: Use the sample data for isolated testing
  Verify API responses: Check Explorium API returns expected data

  Best Practices

  Data Quality

  Complete contact records: Ensure name and company are populated
  Standardize company names: Use official names, not abbreviations
  Include existing emails: Improves match accuracy
  Regular data hygiene: Clean up test and invalid contacts

  Performance Optimization

  Batch size: 6 is optimal for rate limits
  Webhook reliability: Monitor delivery success
  API quotas: Track usage in both platforms
  Execution history: Regularly clean old executions

  Compliance & Privacy

  GDPR compliance: Ensure lawful basis for enrichment
  Data minimization: Only enrich necessary fields
  Access controls: Limit who can modify enriched data
  Audit trail: Document enrichment for compliance

  Customization Options

  Additional Enrichment

  Extend with more Explorium data:

  Job titles and departments
  Social media profiles
  Professional experience
  Skills and interests
  Company information

  Enhanced Processing

  Add workflow logic for:

  Lead scoring based on enrichment
  Routing based on data quality
  Notifications for high-value matches
  Custom field mapping

  Integration Extensions

  Connect to other systems:

  Sync enriched data to CRM
  Trigger marketing automation
  Update data warehouse
  Send notifications to Slack

  API Considerations

  HubSpot Limits

  API calls**: Monitor daily limits
  Webhook payload**: Max 200 contacts per trigger
  Rate limits**: 100 requests per 10 seconds
  Property limits**: Max 1000 custom properties

  Explorium Limits

  Match API**: Batched for efficiency
  Enrichment calls**: Two parallel enrichments
  Rate limits**: Based on your plan
  Data freshness**: Real-time matching

  Architecture Considerations

  This workflow integrates with:

  HubSpot workflows and automation
  Marketing campaigns and sequences
  Sales engagement tools
  Reporting and analytics
  Other enrichment services

  Security Best Practices

  Webhook validation**: Verify requests are from HubSpot
  Token security**: Rotate API tokens regularly
  Access control**: Limit workflow modifications
  Data encryption**: All API calls use HTTPS
  Audit logging**: Track all enrichments

  Advanced Configuration

  Custom Field Mapping

  Modify the Update HubSpot node to map to custom properties:

  // Example custom mapping
  {
    "custom_mobile": "{{ $json.data.mobile_phone }}",
    "custom_linkedin": "{{ $json.data.linkedin_url }}",
    "enrichment_date": "{{ $now.toISO() }}"
  }

  Conditional Processing

  Add logic to process only certain contacts:

  Filter by contact source
  Check for specific properties
  Validate email domains
  Exclude test contacts

  Support Resources

  For assistance:

  n8n issues**: Check n8n documentation and forums
  HubSpot API**: Reference HubSpot developers documentation
  Explorium API**: Contact Explorium support
  Webhook issues**: Use HubSpot webhook testing tools

nodes_used:
  ["n8n-nodes-base.httpRequest","n8n-nodes-base.hubspot","n8n-nodes-base.salesforce","n8n-nodes-base.code"]

workflow_json:
  {"id":"A1ANYPPCR58x29nH","meta":{"instanceId":"0a70652f43c1b29dd16c35b61a38fd31c8004f58bc7e723bf43262a797407c77","templateCredsSetupCompleted":true},"name":"Hubspot -> Salesforce - final","tags":[],"nodes":[{"id":"306813bf-056d-48fc-ba8b-e64ddb01beda","name":"Match_prospect","type":"n8n-nodes-base.httpRequest","position":[-1820,360],"parameters":{"url":"https://api.explorium.ai/v1/prospects/match","method":"POST","options":{},"jsonBody":"={\n  \"prospects_to_match\": [\n    {\n      \"full_name\": \"{{ ($json.properties.firstname.value || '') + ' ' + ($json.properties.lastname.value || '') }}\",\n      \"company_name\": \"{{ ($json.properties.company.value || '').trim() }}\",\n      \"email\": \"{{ $json['identity-profiles'][0].identities.find(id => id.type === 'EMAIL').value }}\"\n    }\n  ]\n}","sendBody":true,"jsonHeaders":"{\n  \"Content-Type\": \"application/json\",\n  \"Accept\": \"application/json\"\n}","sendHeaders":true,"specifyBody":"json","authentication":"genericCredentialType","specifyHeaders":"json","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"85mkGmNNdK1951hF","name":"Header Auth Connection"}},"typeVersion":4.2},{"id":"08e9aa3a-6957-4f88-9ad7-f492652046e4","name":"Extract Prospect IDs from Matched Results","type":"n8n-nodes-base.code","position":[-1380,360],"parameters":{"jsCode":"const allItems = $input.all();\nconst prospectIds = allItems.map(item => \n  item.json.matched_prospects.map(prospect => prospect.prospect_id)\n).flat();\n\nreturn [{\n  json: {\n    prospect_ids: prospectIds\n  }\n}];"},"typeVersion":2},{"id":"e786a130-996c-414a-b87c-aec3a61a960e","name":"Explorium Enrich Contacts Information","type":"n8n-nodes-base.httpRequest","position":[-1160,260],"parameters":{"url":"https://api.explorium.ai/v1/prospects/contacts_information/bulk_enrich","method":"POST","options":{},"jsonBody":"={{ { \"prospect_ids\": $json.prospect_ids } }}","sendBody":true,"jsonHeaders":"{\n  \"Content-Type\": \"application/json\",\n  \"Accept\": \"application/json\"\n}","sendHeaders":true,"specifyBody":"=json","authentication":"genericCredentialType","bodyParameters":{"parameters":[{}]},"specifyHeaders":"json","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"85mkGmNNdK1951hF","name":"Header Auth Connection"}},"typeVersion":4.2},{"id":"205c6a21-e0fd-4963-aacf-8498eba0e838","name":"Merge","type":"n8n-nodes-base.merge","position":[-940,360],"parameters":{"mode":"combine","options":{},"fieldsToMatchString":"data[0].prospect_id"},"typeVersion":3.1},{"id":"faa070fd-841b-460c-b25f-0e3bed266f17","name":"HubSpot Trigger","type":"n8n-nodes-base.hubspotTrigger","position":[-2260,360],"webhookId":"d359fd68-9568-4787-93dd-192be0fda279","parameters":{"eventsUi":{"eventValues":[{}]},"additionalFields":{}},"credentials":{"hubspotDeveloperApi":{"id":"MpQJKDhz8ijUUHzc","name":"HubSpot Developer account"}},"typeVersion":1},{"id":"76b419d5-f31d-4657-8157-a26d83564b2d","name":"HubSpot","type":"n8n-nodes-base.hubspot","position":[-2040,360],"parameters":{"contactId":{"__rl":true,"mode":"id","value":"={{ $input.item.json.contactId }}"},"operation":"get","authentication":"appToken","additionalFields":{}},"credentials":{"hubspotAppToken":{"id":"cBozD4139iWohcJ2","name":"HubSpot App Token account"}},"typeVersion":2.1},{"id":"17e5e938-690b-41f0-b9b1-10981f109f20","name":"Salesforce","type":"n8n-nodes-base.salesforce","position":[-500,360],"parameters":{"company":"={{ $json.experience[0].company.name }}","lastname":"={{ $json.full_name }}","additionalFields":{"city":"={{ $json.city || null }}","email":"={{ $json.professions_email || null }}","phone":"={{ $json.phone_numbers?.[0]?.phone_number || \"null\" }}\n","state":"={{ $json.region_name || '' }}","title":"={{ $json.experience?.[0]?.title?.name || null }}","country":"={{ $json.country_name || null }}","website":"={{ $json.experience?.[0]?.company?.website || null }}","mobilePhone":"={{ $json.mobile_phone }}"}},"credentials":{"salesforceOAuth2Api":{"id":"unhmsSbB64eNwCMO","name":"Salesforce account"}},"typeVersion":1},{"id":"53699185-4fe8-4add-8b6f-4825e481dcf3","name":"Code - flatten","type":"n8n-nodes-base.code","position":[-720,360],"parameters":{"jsCode":"return $input.all().map(item => \n    item.json.data.map(prospect => ({\n      prospect_id: prospect.prospect_id,\n      ...prospect.data\n    }))\n  ).flat()"},"typeVersion":2},{"id":"a39d10c7-e80e-4493-a555-f1fe36216c59","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-3320,80],"parameters":{"width":960,"height":2800,"content":"# Automatically enrich prospect data from HubSpot using Explorium and create leads in Salesforce\n\nThis n8n workflow streamlines the process of enriching prospect information by automatically pulling data from HubSpot, processing it through Explorium's AI-powered tools, and creating new leads in Salesforce with enhanced prospect details.\n\n## Credentials Required\n\nTo use this workflow, set up the following credentials in your n8n environment:\n\n### HubSpot\n- **Type**: App Token (or OAuth2 for broader compatibility)\n- **Used for**: triggering on new contacts, fetching contact data\n\n### Explorium API\n- **Type**: Generic Header Auth\n- **Header**: Authorization\n- **Value**: Bearer YOUR_API_KEY\n\n### Salesforce\n- **Type**: OAuth2 or Username/Password\n- **Used for**: creating new lead records\n\nGo to Settings → Credentials, create these three credentials, and assign them in the respective nodes before running the workflow.\n\n## Workflow Overview\n\n### Node 1: HubSpot Trigger\nThis node listens for real-time events from the connected HubSpot account. Once triggered, the node passes metadata about the event to the next step in the flow.\n\n### Node 2: HubSpot\nThis node fetches contact details from HubSpot after the trigger event.\n\n- **Credential**: Connected using a HubSpot App Token\n- **Resource**: Contact\n- **Operation**: Get Contact\n- **Return All**: Disabled\n\nThis node retrieves the full contact details needed for further processing and enrichment.\n\n### Node 3: Match prospect\nThis node sends each contact's data to Explorium's AI-powered prospect matching API in real time.\n\n- **Method**: POST\n- **Endpoint**: https://api.explorium.ai/v1/prospects/match\n- **Authentication**: Generic Header Auth (using a configured credential)\n- **Headers**: Content-Type: application/json\n\nThe request body is dynamically built from contact data, typically including: full_name, company_name, email, phone_number, linkedin. These fields are matched against Explorium's intelligence graph to return enriched or validated profiles.\n\n**Response Output**: total_matches, matched_prospects, and a prospect_id. Each response is used downstream to enrich, validate, or create lead information.\n\n### Node 4: Filter\nThis node filters the output from the Match prospect step to ensure that only valid, matched results continue in the flow. Only records that contain at least one matched prospect with a non-null prospect_id are passed forward.\n\n**Status**: Currently deactivated (as shown by the \"Deactivate\" label)\n\n### Node 5: Extract Prospect IDs from Matched Results\nThis node extracts all valid prospect_id values from previously matched prospects and compiles them into a flat array. It loops over all matched items, extracts each prospect_id from the matched_prospects array and returns a single object with an array of all prospect_ids.\n\n### Node 6: Explorium Enrich Contacts Information\nThis node performs bulk enrichment of contacts by querying Explorium with a list of matched prospect_ids.\n\n**Node Configuration:**\n- **Method**: POST\n- **Endpoint**: https://api.explorium.ai/v1/prospects/contacts_information/bulk_enrich\n- **Authentication**: Header Auth (using saved credentials)\n- **Headers**: \"Content-Type\": \"application/json\", \"Accept\": \"application/json\"\n\nReturns enriched contact information, such as:\n- **emails**: professional/personal email addresses\n- **phone_numbers**: mobile and work numbers\n- **professions_email**, **professional_email_status**, **mobile_phone**\n\n### Node 7: Explorium Enrich Profiles\nThis additional enrichment node provides supplementary contact data enhancement, running in parallel with the primary enrichment process.\n\n### Node 8: Merge\nThis node combines multiple data streams from the parallel enrichment processes into a single output, allowing you to consolidate data from different Explorium enrichment endpoints. The \"combine\" setting indicates it will merge the incoming data streams rather than overwriting them.\n\n### Node 9: Code - flatten\nThis custom code node processes and transforms the merged enrichment data before creating the Salesforce lead. It can be used to:\n- Flatten nested data structures\n- Format data according to Salesforce field requirements\n- Apply business logic or data validation\n- Map Explorium fields to Salesforce lead properties\n- Handle data type conversions\n\n### Node 10: Salesforce\nThis final node creates new leads in Salesforce using the enriched data returned by Explorium.\n\n- **Credential**: Salesforce OAuth2 or Username/Password\n- **Resource**: Lead\n- **Operation**: Create Lead\n\nThe node creates new lead records with enriched information including contact details, company information, and professional data obtained through the Explorium enrichment process.\n\n## Workflow Flow Summary\n\n1. **Trigger**: HubSpot webhook triggers on new/updated contacts\n2. **Fetch**: Retrieve contact details from HubSpot\n3. **Match**: Find prospect matches using Explorium\n4. **Filter**: Keep only successfully matched prospects (currently deactivated)\n5. **Extract**: Compile prospect IDs for bulk enrichment\n6. **Enrich**: Parallel enrichment of contact information through multiple Explorium endpoints\n7. **Merge**: Combine enrichment results\n8. **Transform**: Flatten and prepare data for Salesforce (Code node)\n9. **Create**: Create new lead records in Salesforce\n\nThis workflow ensures comprehensive data enrichment while maintaining data quality and providing a seamless integration between HubSpot prospect data and Salesforce lead creation. The parallel enrichment structure maximizes data collection efficiency before creating high-quality leads in your CRM system."},"typeVersion":1},{"id":"60f1e6d3-7bbe-435a-85af-59c79f81aa5f","name":"Filter - non matched","type":"n8n-nodes-base.filter","position":[-1600,360],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"6896e951-8d66-41b1-87a5-a96d2e049675","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{ $json.matched_prospects.some(prospect => prospect.prospect_id !== null).toBoolean() }}","rightValue":"null"}]}},"typeVersion":2.2},{"id":"459bb55b-663d-4913-b11a-b3be6b16de06","name":"Explorium Enrich Profiles","type":"n8n-nodes-base.httpRequest","position":[-1160,460],"parameters":{"url":"https://api.explorium.ai/v1/prospects/profiles/bulk_enrich","method":"POST","options":{},"jsonBody":"={{ { \"prospect_ids\": $json.prospect_ids } }}","sendBody":true,"jsonHeaders":"{\n  \"Content-Type\": \"application/json\",\n  \"Accept\": \"application/json\"\n}","sendHeaders":true,"specifyBody":"=json","authentication":"genericCredentialType","bodyParameters":{"parameters":[{}]},"specifyHeaders":"json","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"85mkGmNNdK1951hF","name":"Header Auth Connection"}},"typeVersion":4.2}],"active":true,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"d2824b55-3ef6-41ac-a550-ef8701401167","connections":{"Merge":{"main":[[{"node":"Code - flatten","type":"main","index":0}]]},"HubSpot":{"main":[[{"node":"Match_prospect","type":"main","index":0}]]},"Code - flatten":{"main":[[{"node":"Salesforce","type":"main","index":0}]]},"Match_prospect":{"main":[[{"node":"Filter - non matched","type":"main","index":0}]]},"HubSpot Trigger":{"main":[[{"node":"HubSpot","type":"main","index":0}]]},"Filter - non matched":{"main":[[{"node":"Extract Prospect IDs from Matched Results","type":"main","index":0}]]},"Explorium Enrich Profiles":{"main":[[{"node":"Merge","type":"main","index":1}]]},"Explorium Enrich Contacts Information":{"main":[[{"node":"Merge","type":"main","index":0}]]},"Extract Prospect IDs from Matched Results":{"main":[[{"node":"Explorium Enrich Contacts Information","type":"main","index":0},{"node":"Explorium Enrich Profiles","type":"main","index":0}]]}}}


name: Generate AI Videos with Google Veo3, Save to Google Drive and Upload to YouTube
author_name: Davide
author_username: n3witalia
categories: []
created_at: 2025-06-10T08:27:01.375Z
updated_at: 2025-06-10T08:27:01.375Z
url: https://n8n.io/workflows/4846
scraped_at: 2025-06-19 22:48:34
description:
  This workflow allows users to generate AI videos using Google Veo3, save them to Google Drive, generate optimized YouTube titles with GPT-4o, and automatically upload them to YouTube . The entire process is triggered from a Google Sheet that acts as the central interface for input and output.

  IT automates video creation, uploading, and tracking, ensuring seamless integration between Google Sheets, Google Drive, Google Veo3, and YouTube.

  Benefits of this Workflow

  💡 No Code Interface**: Trigger and control the video production pipeline from a simple Google Sheet.
  ⚙️ Full Automation**: Once set up, the entire video generation and publishing process runs hands-free.
  🧠 AI-Powered Creativity**:

    Generates engaging YouTube titles using GPT-4o.
    Leverages advanced generative video AI from Google Veo3.
  📁 Cloud Storage & Backup**: Stores all generated videos on Google Drive for safekeeping.
  📈 YouTube Ready**: Automatically uploads to YouTube with correct metadata, saving time and boosting visibility.
  🧪 Scalable**: Designed to process multiple video prompts by looping through new entries in Google Sheets.
  🔒 API-First**: Utilizes secure API-based communication for all services.

  How It Works  
  Trigger: The workflow can be started manually ("When clicking ‘Test workflow’") or scheduled ("Schedule Trigger") to run at regular intervals (e.g., every 5 minutes).  
  Fetch Data: The "Get new video" node retrieves unfilled video requests from a Google Sheet (rows where the "VIDEO" column is empty).  
  Video Creation:  
     The "Set data" node formats the prompt and duration from the Google Sheet.  
     The "Create Video" node sends a request to the Fal.run API (Google Veo3) to generate a video based on the prompt.  
  Status Check:  
     The "Wait 60 sec." node pauses execution for 60 seconds.  
     The "Get status" node checks the video generation status. If the status is "COMPLETED," the workflow proceeds; otherwise, it waits again.  
  Video Processing:  
     The "Get Url Video" node fetches the video URL.  
     The "Generate title" node uses OpenAI (GPT-4.1) to create an SEO-optimized YouTube title.  
     The "Get File Video" node downloads the video file.  
  Upload & Update:  
     The "Upload Video" node saves the video to Google Drive.  
     The "HTTP Request" node uploads the video to YouTube via the Upload-Post API.  
     The "Update Youtube URL" and "Update result" nodes update the Google Sheet with the video URL and YouTube link.  

  Set Up Steps  
  Google Sheet Setup:  
     Create a Google Sheet with columns: PROMPT, DURATION, VIDEO, and YOUTUBE_URL.  
     Share the Sheet link in the "Get new video" node.  

  API Keys:  
     Obtain a Fal.run API key (for Veo3) and set it in the "Create Video" node (Header: Authorization: Key YOURAPIKEY).  
     Get an Upload-Post API key (for YouTube uploads) and configure the "HTTP Request" node (Header: Authorization: Apikey YOUR_API_KEY).  

  YouTube Upload Configuration:  
     Replace YOUR_USERNAME in the "HTTP Request" node with your Upload-Post profile name.  

  Schedule Trigger:  
     Configure the "Schedule Trigger" node to run periodically (e.g., every 5 minutes).  

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

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

workflow_json:
  {"id":"g1hmK8jw38TOYX7D","meta":{"instanceId":"a4bfc93e975ca233ac45ed7c9227d84cf5a2329310525917adaf3312e10d5462","templateCredsSetupCompleted":true},"name":"Create Video with Google Veo3 and Upload to Youtube","tags":[],"nodes":[{"id":"f1fcb9ab-37aa-44a3-91fc-8480351aa5cd","name":"When clicking ‘Test workflow’","type":"n8n-nodes-base.manualTrigger","position":[-220,840],"parameters":{},"typeVersion":1},{"id":"58194812-a64d-401e-be5e-2f1ba9210557","name":"Get status","type":"n8n-nodes-base.httpRequest","position":[840,840],"parameters":{"url":"=https://queue.fal.run/fal-ai/veo3/requests/{{ $('Create Video').item.json.request_id }}/status ","options":{},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"daOZafXpRXLtoLUV","name":"Fal.run API"}},"typeVersion":4.2},{"id":"1e23339c-f829-4426-b4f6-b02add8f8c5e","name":"Wait 60 sec.","type":"n8n-nodes-base.wait","position":[660,840],"webhookId":"490facb8-d0ae-402e-ab59-a87720cf0bdd","parameters":{"amount":60},"typeVersion":1.1},{"id":"98ad8a6d-9ded-4f4e-a4ef-b624f7fe7e39","name":"Schedule Trigger","type":"n8n-nodes-base.scheduleTrigger","position":[-220,700],"parameters":{"rule":{"interval":[{"field":"minutes"}]}},"typeVersion":1.2},{"id":"262608c6-e905-4d16-bc52-22b67c1bc298","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[-220,-460],"parameters":{"color":3,"width":740,"height":280,"content":"# Generate AI Videos with Google Veo3, Save to Google Drive and Upload to YouTube\n\nThis workflow allows users to **generate AI videos** using **Google Veo3**, save them to **Google Drive**, generate optimized YouTube titles with GPT-4o, and **automatically upload them to YouTube** . The entire process is triggered from a Google Sheet that acts as the central interface for input and output.\n\nIT automates video creation, uploading, and tracking, ensuring seamless integration between Google Sheets, Google Drive, Google Veo3, and YouTube.\n\n\n\n\n"},"typeVersion":1},{"id":"1ea1879e-1e8e-42f9-8b11-7f771cfca2f8","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-220,-140],"parameters":{"width":740,"height":200,"content":"## STEP 1 - GOOGLE SHEET\nCreate a [Google Sheet like this](https://docs.google.com/spreadsheets/d/1pcoY9N_vQp44NtSRR5eskkL5Qd0N0BGq7Jh_4m-7VEQ/edit?usp=sharing).\n\nPlease insert:\n- in the \"PROMPT\" column the accurate description of the video you want to create\n- in the \"DURATION\" column the lenght of the video you want to create\n\nLeave the \"VIDEO\" column unfilled. It will be inserted by the system once the video has been created"},"typeVersion":1},{"id":"8c54b723-d0b9-4d89-8150-975306640a96","name":"Completed?","type":"n8n-nodes-base.if","position":[1020,840],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"383d112e-2cc6-4dd4-8985-f09ce0bd1781","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.status }}","rightValue":"COMPLETED"}]}},"typeVersion":2.2},{"id":"1135e1f0-b605-4724-a8b3-7f16b9887ef7","name":"Update result","type":"n8n-nodes-base.googleSheets","position":[860,1100],"parameters":{"columns":{"value":{"VIDEO":"={{ $('Get Url Video').item.json.video.url }}","row_number":"={{ $('Get new video').item.json.row_number }}"},"schema":[{"id":"PROMPT","type":"string","display":true,"removed":false,"required":false,"displayName":"PROMPT","defaultMatch":false,"canBeUsedToMatch":true},{"id":"DURATION","type":"string","display":true,"removed":false,"required":false,"displayName":"DURATION","defaultMatch":false,"canBeUsedToMatch":true},{"id":"VIDEO","type":"string","display":true,"removed":false,"required":false,"displayName":"VIDEO","defaultMatch":false,"canBeUsedToMatch":true},{"id":"YOUTUBE_URL","type":"string","display":true,"removed":false,"required":false,"displayName":"YOUTUBE_URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":false,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["row_number"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/11ebWJvwwXHgvQld9kxywKQUvIoBw6xMa0g0BuIqHDxE/edit#gid=0","cachedResultName":"Foglio1"},"documentId":{"__rl":true,"mode":"list","value":"1pcoY9N_vQp44NtSRR5eskkL5Qd0N0BGq7Jh_4m-7VEQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1pcoY9N_vQp44NtSRR5eskkL5Qd0N0BGq7Jh_4m-7VEQ/edit?usp=drivesdk","cachedResultName":"Video Google Veo3"}},"credentials":{"googleSheetsOAuth2Api":{"id":"JYR6a64Qecd6t8Hb","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"8d0ac30d-5a92-487b-aaff-f761bd720293","name":"Set data","type":"n8n-nodes-base.set","position":[220,840],"parameters":{"options":{},"assignments":{"assignments":[{"id":"c713d31f-9abd-496a-ac79-e8e2efe60aa0","name":"prompt","type":"string","value":"={{ $json.PROMPT }}\n\nDuration of the video: {{ $json.DURATION }}"}]}},"typeVersion":3.4},{"id":"ae68690d-c154-4ec9-a5b8-ba95137d2cf4","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-220,520],"parameters":{"width":740,"height":100,"content":"## STEP 4 - MAIN FLOW\nStart the workflow manually or periodically by hooking the \"Schedule Trigger\" node. It is recommended to set it at 5 minute intervals."},"typeVersion":1},{"id":"429ab164-e165-409c-adc7-8a80c25b9f7d","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-220,100],"parameters":{"width":740,"height":140,"content":"## STEP 2 - GET API KEY (YOURAPIKEY)\nCreate an account [here](https://fal.ai/) and obtain API KEY.\nIn the node \"Create Image\" set \"Header Auth\" and set:\n- Name: \"Authorization\"\n- Value: \"Key YOURAPIKEY\""},"typeVersion":1},{"id":"868339d3-e3f0-473b-9f1f-c7c4fe9c9898","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[400,780],"parameters":{"width":180,"height":200,"content":"Set API Key created in Step 2"},"typeVersion":1},{"id":"44793285-6bb8-471a-a632-e0fe33d2d047","name":"Get new video","type":"n8n-nodes-base.googleSheets","position":[0,840],"parameters":{"options":{},"filtersUI":{"values":[{"lookupColumn":"VIDEO"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1pcoY9N_vQp44NtSRR5eskkL5Qd0N0BGq7Jh_4m-7VEQ/edit#gid=0","cachedResultName":"Foglio1"},"documentId":{"__rl":true,"mode":"list","value":"1pcoY9N_vQp44NtSRR5eskkL5Qd0N0BGq7Jh_4m-7VEQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1pcoY9N_vQp44NtSRR5eskkL5Qd0N0BGq7Jh_4m-7VEQ/edit?usp=drivesdk","cachedResultName":"Video Google Veo3"}},"credentials":{"googleSheetsOAuth2Api":{"id":"JYR6a64Qecd6t8Hb","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"7271ea9a-c4f5-4091-8f0f-ef40bb1d94af","name":"Create Video","type":"n8n-nodes-base.httpRequest","position":[440,840],"parameters":{"url":"https://queue.fal.run/fal-ai/veo3","method":"POST","options":{},"jsonBody":"={\n     \"prompt\": \"{{$json.prompt}}\"\n}","sendBody":true,"sendHeaders":true,"specifyBody":"json","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth","headerParameters":{"parameters":[{"name":"Content-Type","value":"application/json"}]}},"credentials":{"httpHeaderAuth":{"id":"daOZafXpRXLtoLUV","name":"Fal.run API"}},"typeVersion":4.2},{"id":"f0cbd048-011e-47ee-8840-af630adf6f85","name":"Get Url Video","type":"n8n-nodes-base.httpRequest","position":[-220,1220],"parameters":{"url":"=https://queue.fal.run/fal-ai/veo3/requests/{{ $json.request_id }}","options":{},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"daOZafXpRXLtoLUV","name":"Fal.run API"}},"typeVersion":4.2},{"id":"f48cef5b-0609-417b-b4ec-21614397cb07","name":"Get File Video","type":"n8n-nodes-base.httpRequest","position":[400,1220],"parameters":{"url":"={{ $('Get Url Video').item.json.video.url }}","options":{}},"typeVersion":4.2},{"id":"2cde22e1-1b71-4672-80dc-4992c4bdfe5d","name":"Upload Video","type":"n8n-nodes-base.googleDrive","position":[680,1100],"parameters":{"name":"={{ $now.format('yyyyLLddHHmmss') }}-{{ $('Get Url Video').item.json.video.file_name }}","driveId":{"__rl":true,"mode":"list","value":"My Drive"},"options":{},"folderId":{"__rl":true,"mode":"list","value":"1aHRwLWyrqfzoVC8HoB-YMrBvQ4tLC-NZ","cachedResultUrl":"https://drive.google.com/drive/folders/1aHRwLWyrqfzoVC8HoB-YMrBvQ4tLC-NZ","cachedResultName":"Fal.run"}},"credentials":{"googleDriveOAuth2Api":{"id":"HEy5EuZkgPZVEa9w","name":"Google Drive account (n3w.it)"}},"typeVersion":3},{"id":"bf77f692-8a47-4f49-883b-ba045cb39f3b","name":"HTTP Request","type":"n8n-nodes-base.httpRequest","position":[680,1320],"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 title').item.json.message.content }}"},{"name":"user","value":"YOUR_USERNAME"},{"name":"platform[]","value":"youtube"},{"name":"video","parameterType":"formBinaryData","inputDataFieldName":"data"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"DEE2XGvhGodgbAJh","name":"Upload-post.com API"}},"typeVersion":4.2},{"id":"0fab9370-c079-40c8-9e87-e9b319e0bee7","name":"Generate title","type":"@n8n/n8n-nodes-langchain.openAi","position":[20,1220],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"GPT-4O-MINI"},"options":{},"messages":{"values":[{"content":"=Input: {{ $('Get new video').item.json.PROMPT }}"},{"role":"system","content":"You are a YouTube SEO expert specialized in creating engaging and optimized titles.\n\nYour task is to generate an effective title for a YouTube video based on the user's video description.\n\nGUIDELINES:\n- Maximum 60 characters to avoid truncation\n- Use relevant keywords for SEO\n- Make the title catchy and clickable\n- Avoid excessive or misleading clickbait\n- Consider the target audience of the content\n- Use numbers, questions, or power words when appropriate\n- IMPORTANT: Generate the title in the same language as the input description\n\nOUTPUT FORMAT:\nProvide only the title, without additional explanations.\n\nEXAMPLE:\nInput: \"Tutorial video on how to cook perfect pasta carbonara\"\nOutput: \"PERFECT Carbonara in 10 Minutes - Chef's Secrets\""}]}},"credentials":{"openAiApi":{"id":"TefveNaDaMERl1hY","name":"OpenAi account (Eure)"}},"typeVersion":1.8},{"id":"cf9a58f0-0523-4229-ac2e-42f0f71d5306","name":"Update Youtube URL","type":"n8n-nodes-base.googleSheets","position":[860,1320],"parameters":{"columns":{"value":{"VIDEO":"=","row_number":"={{ $('Get new video').item.json.row_number }}","YOUTUBE_URL":"https://youtu.be/{{ $json.results.youtube.video_id }}"},"schema":[{"id":"PROMPT","type":"string","display":true,"removed":false,"required":false,"displayName":"PROMPT","defaultMatch":false,"canBeUsedToMatch":true},{"id":"DURATION","type":"string","display":true,"removed":false,"required":false,"displayName":"DURATION","defaultMatch":false,"canBeUsedToMatch":true},{"id":"VIDEO","type":"string","display":true,"removed":false,"required":false,"displayName":"VIDEO","defaultMatch":false,"canBeUsedToMatch":true},{"id":"YOUTUBE_URL","type":"string","display":true,"removed":false,"required":false,"displayName":"YOUTUBE_URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":false,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["row_number"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/11ebWJvwwXHgvQld9kxywKQUvIoBw6xMa0g0BuIqHDxE/edit#gid=0","cachedResultName":"Foglio1"},"documentId":{"__rl":true,"mode":"list","value":"1pcoY9N_vQp44NtSRR5eskkL5Qd0N0BGq7Jh_4m-7VEQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1pcoY9N_vQp44NtSRR5eskkL5Qd0N0BGq7Jh_4m-7VEQ/edit?usp=drivesdk","cachedResultName":"Video Google Veo3"}},"credentials":{"googleSheetsOAuth2Api":{"id":"JYR6a64Qecd6t8Hb","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"2f97346c-78df-41fe-b15d-c2af7e9ee680","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[660,1260],"parameters":{"width":180,"height":200,"content":"Set YOUR_USERNAME in Step 3"},"typeVersion":1},{"id":"0d6517cb-d2a3-4afe-b163-25311faed711","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[-220,280],"parameters":{"width":740,"height":200,"content":"## STEP 3 - Upload video on Youtube\n- Find your API key in your [Upload-Post Manage Api Keys](https://app.upload-post.com/) 10 FREE uploads per month\n- Set the the \"Auth Header\":\n-- Name: Authorization\n-- Value: Apikey YOUR_API_KEY_HERE\n- Create profiles to manage your social media accounts. The \"Profile\" you choose will be used in the field YOUR_USRNAME (eg. test1 or test2).  "},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"a358d31a-ae0a-44e0-83e4-0a0df359e143","connections":{"Set data":{"main":[[{"node":"Create Video","type":"main","index":0}]]},"Completed?":{"main":[[{"node":"Get Url Video","type":"main","index":0}],[{"node":"Wait 60 sec.","type":"main","index":0}]]},"Get status":{"main":[[{"node":"Completed?","type":"main","index":0}]]},"Create Video":{"main":[[{"node":"Wait 60 sec.","type":"main","index":0}]]},"HTTP Request":{"main":[[{"node":"Update Youtube URL","type":"main","index":0}]]},"Upload Video":{"main":[[{"node":"Update result","type":"main","index":0}]]},"Wait 60 sec.":{"main":[[{"node":"Get status","type":"main","index":0}]]},"Get Url Video":{"main":[[{"node":"Generate title","type":"main","index":0}]]},"Get new video":{"main":[[{"node":"Set data","type":"main","index":0}]]},"Update result":{"main":[[]]},"Generate title":{"main":[[{"node":"Get File Video","type":"main","index":0}]]},"Get File Video":{"main":[[{"node":"Upload Video","type":"main","index":0},{"node":"HTTP Request","type":"main","index":0}]]},"When clicking ‘Test workflow’":{"main":[[{"node":"Get new video","type":"main","index":0}]]}}}


name: Generate and Send AI News Newsletters Automatically with GPT & Gmail
author_name: Rahul Joshi
author_username: rahul08
categories: []
created_at: 2025-06-10T08:27:24.513Z
updated_at: 2025-06-10T08:27:24.513Z
url: https://n8n.io/workflows/4847
scraped_at: 2025-06-19 22:48:55
description:
  Description:

  Automate your AI newsletter creation and delivery using this ready-to-deploy n8n workflow template. Powered by GPT (OpenAI/Azure) and integrated with Gmail, this workflow generates rich, structured, and engaging AI-focused newsletters and sends them out daily or weekly—completely hands-free.

  What It Does:

  📰 Fetches the latest AI trends and updates using GPT
  ✍️ Automatically formats news into structured newsletter sections: headlines, tools, stats, tips, and more
  📧 Sends HTML email newsletters via Gmail
  🕘 Runs automatically at your chosen schedule (default: 9 AM daily)

  Setup Includes:

  Connect your OpenAI or Azure GPT API
  Add Gmail SMTP or OAuth credentials
  Customize categories, schedule, and email styling

  Perfect for:

  Tech bloggers, content marketers, AI influencers, and automation enthusiasts who want to send curated AI content to their audience without manual effort.

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

workflow_json:
  {"id":"DSxmKG8H861zKUw8","meta":{"instanceId":"18c9b77a7db94bab09d77f4a9c44dd94853695bba1618cb7bc3c4bc412c07c1e","templateCredsSetupCompleted":true},"name":"AI Generated Email Newsletter","tags":[],"nodes":[{"id":"a915b64b-1052-4cd1-aca9-0325c1b2c29d","name":"Workflow Documentation","type":"n8n-nodes-base.stickyNote","position":[-120,-140],"parameters":{"color":6,"width":450,"height":420,"content":"## Daily AI News Summary Workflow\n\nThis workflow runs every day at 9 AM to:\n\n1. **Fetch Latest AI News**: Uses Perplexity to find recent AI developments\n2. **Categorize Content**: Organizes news into three key areas:\n   - 🚀 New Technology (breakthroughs, models, research)\n   - 💡 Tips & Tricks (practical applications, tutorials)\n   - 🛡️ AI Ethics & Security (privacy, safety, regulations)\n3. **Format & Send**: Creates a beautiful HTML email with summaries and links\n\n### Setup Required:\n- Perplexity API credentials\n- SMTP email credentials\n- Update recipient email address\n\n### Customization:\n- Change schedule time in Daily Trigger\n- Modify categories in Perplexity prompt\n- Adjust email styling in Format Email Content node"},"typeVersion":1},{"id":"3c6ef52a-3c4b-4d0e-be08-d496c407fa66","name":"Setup Instructions","type":"n8n-nodes-base.stickyNote","position":[480,0],"parameters":{"color":3,"width":580,"height":280,"content":"⚙️ **Configuration Needed:**\n\n1. **AI Agent**: Add your Chat Model API key to the \"AI Agent\"\n\n2. **Email Settings**: \n   - Add your Gmail Credentials\n   - Add subject and message seperately\n   - Email should be in HTML format\n\n3. **Timing**: Modify schedule in \"Daily Trigger\" if you want different timing\n\n4. **Content**: Customize the news categories or add more in the AI Agent prompt"},"typeVersion":1},{"id":"2f165ff5-7666-4f7b-93e0-73556ad9ed7a","name":"Set Dates1","type":"n8n-nodes-base.set","position":[60,360],"parameters":{"options":{},"assignments":{"assignments":[{"id":"current-date","name":"currentDate","type":"string","value":"={{ $now.format('yyyy-MM-dd') }}"},{"id":"yesterday-date","name":"lastweekDate","type":"string","value":"={{ $now.minus({days: 7}).format('yyyy-MM-dd') }}"}]}},"typeVersion":3.4},{"id":"419a0eac-33f1-4349-ba54-a0a428ef8c1b","name":"Gmail1","type":"n8n-nodes-base.gmail","position":[880,360],"webhookId":"6e5776e8-b6b9-4c56-8b3a-812f68959433","parameters":{"sendTo":"jyothi.swarup@techdome.net.in","message":"={{ $json.html }}","options":{},"subject":"={{ $json.subject }}"},"credentials":{"gmailOAuth2":{"id":"kqndcZ7sNbQqDrJF","name":"Gmail account"}},"typeVersion":2.1},{"id":"57cb8666-b3ff-489b-a6a5-be329ad82ab5","name":"Format Email Content","type":"n8n-nodes-base.code","position":[660,360],"parameters":{"jsCode":"// n8n Code Node - Email Formatter for AI Newsletter\n// This code formats the AI agent output for email sending\n\n// Get the AI agent output from the previous node\nconst aiOutput = $input.all()[0].json.output || $input.all()[0].json.text || $input.all()[0].json;\n\n// Extract the newsletter content (remove the prefix text)\nlet newsletterContent = '';\nif (typeof aiOutput === 'object' && aiOutput.content) {\n  newsletterContent = aiOutput.content;\n} else if (typeof aiOutput === 'string') {\n  // Remove the \"this is the output from the ai agent:\" prefix if it exists\n  newsletterContent = aiOutput.replace(/^this is the output from the ai agent:\\s*/i, '');\n} else {\n  newsletterContent = JSON.stringify(aiOutput);\n}\n\n// Clean up the newsletter content - remove \\n literals and format properly\nnewsletterContent = newsletterContent\n  .replace(/\\\\n/g, '\\n')  // Convert literal \\n to actual newlines\n  .replace(/^\\s+|\\s+$/g, '')  // Trim whitespace\n  .replace(/\\n{3,}/g, '\\n\\n');  // Replace multiple newlines with double newlines\n\n// Generate email subject with current date\nfunction generateEmailSubject() {\n  const currentDate = new Date().toLocaleDateString('en-US', { \n    year: 'numeric', \n    month: 'long', \n    day: 'numeric' \n  });\n  return `🤖 AI Weekly Pulse - ${currentDate}: ChatGPT Voice Update & Latest AI News`;\n}\n\n// Generate email body with proper formatting\nfunction generateEmailBody() {\n  const emailBody = `Hi there!\n\nI hope this email finds you well. Here's this week's AI newsletter with the latest updates from the AI world:\n\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n${newsletterContent}\n\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\nHope you found this week's AI updates valuable! Feel free to reply with your thoughts or questions.\n\nBest regards,\nAI Weekly Pulse Team\n\n---\n📧 This newsletter was automatically generated and sent via n8n automation.\n🔗 Want to unsubscribe or have questions? Just reply to this email.`;\n\n  return emailBody;\n}\n\n// Generate HTML version of the email for better formatting\nfunction generateHTMLEmailBody() {\n  // Convert markdown-like content to basic HTML\n  let htmlContent = newsletterContent\n    .replace(/^# (.*$)/gm, '<h1 style=\"color: #333; border-bottom: 2px solid #667eea; padding-bottom: 10px;\">$1</h1>')\n    .replace(/^## (.*$)/gm, '<h2 style=\"color: #444; margin-top: 30px; margin-bottom: 15px;\">$1</h2>')\n    .replace(/^### (.*$)/gm, '<h3 style=\"color: #555; margin-top: 20px; margin-bottom: 10px;\">$1</h3>')\n    .replace(/\\*\\*(.*?)\\*\\*/g, '<strong>$1</strong>')\n    .replace(/\\*(.*?)\\*/g, '<em>$1</em>')\n    .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\" style=\"color: #667eea; text-decoration: none;\">$1</a>')\n    .replace(/^- (.*$)/gm, '<li style=\"margin-bottom: 8px;\">$1</li>')\n    .replace(/^> (.*$)/gm, '<blockquote style=\"border-left: 4px solid #667eea; padding-left: 20px; margin: 20px 0; font-style: italic; color: #666;\">$1</blockquote>')\n    .replace(/---/g, '<hr style=\"border: none; border-top: 2px solid #eee; margin: 30px 0;\">')\n    .replace(/\\n\\n/g, '</p><p style=\"line-height: 1.6; margin-bottom: 15px;\">')\n    .replace(/\\n/g, '<br>');\n\n  // Wrap list items in ul tags\n  htmlContent = htmlContent.replace(/(<li[^>]*>.*?<\\/li>)/gs, '<ul style=\"padding-left: 20px; margin-bottom: 20px;\">$1</ul>');\n\n  const htmlBody = `\n<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>AI Weekly Pulse</title>\n</head>\n<body style=\"font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 0 auto; padding: 20px; background-color: #f9f9f9;\">\n    <div style=\"background: white; padding: 40px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.1);\">\n        <div style=\"text-align: center; margin-bottom: 30px; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 8px; color: white;\">\n            <h1 style=\"margin: 0; font-size: 24px;\">🤖 AI Weekly Pulse</h1>\n            <p style=\"margin: 10px 0 0 0; opacity: 0.9;\">Your Weekly Dose of AI Innovation</p>\n        </div>\n        \n        <div style=\"margin-bottom: 30px;\">\n            <p style=\"font-size: 16px; color: #555;\">Hi there!</p>\n            <p style=\"font-size: 16px; color: #555;\">Hope this email finds you well. Here's this week's AI newsletter with the latest updates from the AI world:</p>\n        </div>\n        \n        <div style=\"background: #fafafa; padding: 30px; border-radius: 8px; margin: 20px 0;\">\n            <p style=\"line-height: 1.6; margin-bottom: 15px;\">${htmlContent}</p>\n        </div>\n        \n        <div style=\"margin-top: 40px; padding: 30px; background: #f0f4ff; border-radius: 8px; text-align: center;\">\n            <p style=\"font-size: 16px; color: #555; margin-bottom: 15px;\">Hope you found this week's AI updates valuable!</p>\n            <p style=\"font-size: 16px; color: #555; margin-bottom: 20px;\">Feel free to reply with your thoughts or questions.</p>\n            <p style=\"font-size: 18px; color: #333; margin: 0;\"><strong>Best regards,<br>AI Weekly Pulse Team</strong></p>\n        </div>\n        \n        <div style=\"margin-top: 30px; padding: 20px; background: #e8f2ff; border-radius: 8px; font-size: 14px; color: #666; text-align: center;\">\n            <p style=\"margin: 5px 0;\">📧 This newsletter was automatically generated and sent via n8n automation.</p>\n            <p style=\"margin: 5px 0;\">🔗 Want to unsubscribe or have questions? Just reply to this email.</p>\n        </div>\n    </div>\n</body>\n</html>`;\n\n  return htmlBody;\n}\n\n// Generate the formatted output for the email node\nconst emailSubject = generateEmailSubject();\nconst emailBodyText = generateEmailBody();\nconst emailBodyHTML = generateHTMLEmailBody();\n\n// Return the formatted data for the next node (email sender)\nreturn [\n  {\n    json: {\n      subject: emailSubject,\n      text: emailBodyText,\n      html: emailBodyHTML,\n      // Additional metadata\n      newsletter_content: newsletterContent,\n      generated_at: new Date().toISOString(),\n      email_type: \"ai_weekly_pulse\"\n    }\n  }\n];"},"typeVersion":2},{"id":"9a9676bb-d645-49fc-84ab-5a5c0cd92645","name":"AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[280,360],"parameters":{"text":"=Newsletter Structure\n1. Title\nEngaging and punchy (under 10 words).\n\nIncludes a relevant keyword (e.g., “AI”, “ChatGPT”, “Machine Learning”).\n\n2. Editor’s Note (Optional but preferred)\nA short 2–3 sentence personal note to the readers.\n\nTone: Conversational and warm.\n\nSummarize the theme of this issue or highlight an AI trend to watch.\n\n3. 🧠 AI in Focus (Main Story)\nOne key development or trend in AI this week.\n\nCould be about a breakthrough, a major product launch, a regulatory move, or a case study.\n\n3–5 paragraphs long.\n\nInclude context (why it matters), impact, and your analysis.\n\n4. 📰 Headlines in AI (News Roundup)\nList 3–5 bite-sized headlines with 1–2 sentence summaries for each. Include:\n\nDate (optional).\n\nSource (e.g., OpenAI, Google, MIT, etc.).\n\nLink (if available).\n\nExample:\n\nOpenAI Releases GPT-5 Preview – OpenAI teased major upgrades in language understanding and reasoning. Read more\n\n5. 🔍 Tool of the Week\nIntroduce one new or underrated AI tool.\n\nInclude what it does, who it’s for, and how it works (2–3 sentences).\n\nInclude a link if available.\n\n6. 📚 Learning Corner\nRecommend one AI resource: a blog post, YouTube video, podcast, free course, or paper.\n\nMention why it’s worth reading/listening/watching.\n\n7. 🤖 Prompt of the Week\nShare a powerful or creative prompt users can try with ChatGPT or any LLM.\n\nExplain what it does and when to use it.\n\n8. 📈 AI Stat of the Week\nShare one interesting stat about AI.\n\nCite the source and explain the takeaway in 1–2 sentences.\n\n9. 👥 Community Shoutout (Optional)\nHighlight a person, open-source project, or discussion in the AI community.\n\n10. 👀 What to Watch Next Week\nPreview an upcoming event, release, or expected trend in AI.\n\nKeep it short (1–2 sentences).\n\n🧾 Style Guidelines\nUse markdown for formatting: **bold**, # headers, - lists, etc.\n\nKeep tone informative, clear, and slightly casual.\n\nAvoid jargon unless explained.\n\nUse bullet points and subheaders for readability.\n\nProvide citations for all the topics immediately ","options":{"systemMessage":"You are an AI writing assistant tasked with creating a weekly newsletter about artificial intelligence (AI). The goal is to inform, engage, and educate readers ranging from tech-savvy professionals to curious enthusiasts. Follow the structure below and ensure the tone is professional yet accessible."},"promptType":"define"},"typeVersion":1.9},{"id":"4e5e19a9-b05f-4ef0-a432-a0e72c479095","name":"Azure OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatAzureOpenAi","position":[260,520],"parameters":{"model":"gpt-4.1","options":{}},"credentials":{"azureOpenAiApi":{"id":"gDiLXmZSX0q3CyLu","name":"Azure Open AI account"}},"typeVersion":1},{"id":"e7dbd62a-6580-4a28-ab85-5fdf885dacf0","name":"Schedule Trigger","type":"n8n-nodes-base.scheduleTrigger","position":[-140,360],"parameters":{"rule":{"interval":[{}]}},"typeVersion":1.2}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"e0cf8d41-3776-4aab-a5ec-fd16b8bc7457","connections":{"AI Agent":{"main":[[{"node":"Format Email Content","type":"main","index":0}]]},"Set Dates1":{"main":[[{"node":"AI Agent","type":"main","index":0}]]},"Schedule Trigger":{"main":[[{"node":"Set Dates1","type":"main","index":0}]]},"Format Email Content":{"main":[[{"node":"Gmail1","type":"main","index":0}]]},"Azure OpenAI Chat Model":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":0}]]}}}


name: Automated Music Video Creation & YouTube Publishing with AI-Generated Metadata from Google Drive
author_name: danejw
author_username: danejw
categories: []
created_at: 2025-06-10T09:31:31.721Z
updated_at: 2025-06-10T09:31:31.721Z
url: https://n8n.io/workflows/4848
scraped_at: 2025-06-19 22:49:13
description:
  The Problem That it Solves

  Uploading music manually to YouTube is a chore. Renaming files, filling metadata, picking the right playlist, adding keywords, and scheduling the release can eat up your creative time. This workflow removes the busy work so you can focus on making tracks instead of managing uploads.

  How it works
  Drop an MP3 into your shared Google Drive “Audio” folder and walk away. The workflow detects the new file, grabs the genre from the filename based on a set of keywords, uses the genre to map to cover art styles, and YouTube playlists, generates the description and tags for YouTube metadata, and schedules and posts to YouTube channel, while sending messages to discord for updates.

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

workflow_json:
  {"id":"AJt025gDBAUD2X5a","meta":{"instanceId":"51b90de3801d5692ca397de394447e07bae7e35aa9a27ffdc72d65d9d40f8ec7","templateCredsSetupCompleted":true},"name":"GoogleUpload_To_Youtube","tags":[],"nodes":[{"id":"f82cc585-06fa-44bb-871d-30533e16b101","name":"Watch New Song in Drive","type":"n8n-nodes-base.googleDriveTrigger","position":[-2660,-240],"parameters":{},"typeVersion":1},{"id":"8064ff79-4890-4d6a-96d3-cfae1cc1509e","name":"Description","type":"@n8n/n8n-nodes-langchain.openAi","notes":"Attempt failed so retrying","position":[-580,-240],"parameters":{},"notesInFlow":true,"retryOnFail":true,"typeVersion":1.8,"waitBetweenTries":3000},{"id":"8b8ce21e-5185-4248-943f-beca41463a5a","name":"Transcribe","type":"@n8n/n8n-nodes-langchain.openAi","position":[-860,-240],"parameters":{},"typeVersion":1.8},{"id":"725ce27c-14ed-4f89-b46c-4fcd8a3f260d","name":"Image Prompt","type":"@n8n/n8n-nodes-langchain.openAi","notes":"Attempt failed so retrying","maxTries":5,"position":[1660,-220],"parameters":{},"notesInFlow":true,"retryOnFail":true,"typeVersion":1.8,"waitBetweenTries":3000},{"id":"bdf778fc-2a32-4173-99e5-8241821c8cb6","name":"Cover Art","type":"@n8n/n8n-nodes-langchain.openAi","position":[2700,-200],"parameters":{},"typeVersion":1.8},{"id":"899252bc-900e-4aa1-8819-c2c891cbacb5","name":"Upload Art","type":"n8n-nodes-base.googleDrive","position":[2980,-200],"parameters":{},"retryOnFail":true,"typeVersion":3,"waitBetweenTries":3000},{"id":"4de56e78-f708-4af7-ab58-e1f0639a9aa0","name":"Download Audio","type":"n8n-nodes-base.googleDrive","position":[-1520,-240],"parameters":{},"retryOnFail":true,"typeVersion":3},{"id":"d3b55cc0-23f9-471a-b286-f2de92dda779","name":"Combine Audio + Image","type":"n8n-nodes-base.httpRequest","position":[4760,40],"parameters":{},"retryOnFail":true,"typeVersion":1,"waitBetweenTries":5000},{"id":"267eb4c6-dcff-493b-ae9d-929cae87cb90","name":"Upload","type":"n8n-nodes-base.youTube","position":[1300,1240],"parameters":{},"typeVersion":1},{"id":"0452bb88-7ba8-4d1d-85d5-e5802409ba86","name":"Tags","type":"@n8n/n8n-nodes-langchain.openAi","notes":"Attempt failed so retrying","position":[-1520,1240],"parameters":{},"notesInFlow":true,"retryOnFail":true,"typeVersion":1.8,"waitBetweenTries":3000},{"id":"ed6dacad-465b-45e6-81f4-39ed6eed8303","name":"Get Schedule","type":"n8n-nodes-base.googleSheets","position":[-580,1240],"parameters":{},"typeVersion":4.6},{"id":"1e97bcd5-7390-4434-80f3-5bd74922d8d8","name":"Update Row","type":"n8n-nodes-base.googleSheets","position":[2540,1240],"parameters":{},"typeVersion":4.6},{"id":"cd21a75a-8182-47b9-8e53-43f49ff9f6ce","name":"Add","type":"n8n-nodes-base.dateTime","position":[80,1240],"parameters":{},"typeVersion":2},{"id":"11480187-e6a8-481c-9236-25e8af52b92b","name":"If","type":"n8n-nodes-base.if","position":[2240,-220],"parameters":{},"typeVersion":2.2},{"id":"9d66c0a3-cd43-4ed9-ba3f-7d1cd41b7b38","name":"Search Art","type":"n8n-nodes-base.googleDrive","position":[2040,-220],"parameters":{},"retryOnFail":true,"typeVersion":3,"alwaysOutputData":true,"waitBetweenTries":3000},{"id":"3ee9c7e8-1393-4fde-ad47-3d16972e013e","name":"Search Video","type":"n8n-nodes-base.googleDrive","position":[3900,-200],"parameters":{},"retryOnFail":true,"typeVersion":3,"alwaysOutputData":true,"waitBetweenTries":3000},{"id":"7702185f-e340-45a8-b5c1-cb28011828be","name":"Download Video","type":"n8n-nodes-base.googleDrive","position":[1100,1240],"parameters":{},"retryOnFail":true,"typeVersion":3},{"id":"c9aadcab-2681-4c19-bb67-9bbbca58d274","name":"If1","type":"n8n-nodes-base.if","position":[4160,-200],"parameters":{},"typeVersion":2.2},{"id":"c67a7679-b46b-4e28-8480-ec5a73d94d0b","name":"Delete Art","type":"n8n-nodes-base.googleDrive","position":[2460,-400],"parameters":{},"retryOnFail":true,"typeVersion":3,"waitBetweenTries":3000},{"id":"53e5077e-1455-4a2e-b998-f16f0b1e278d","name":"Delete Video","type":"n8n-nodes-base.googleDrive","position":[4420,-320],"parameters":{},"retryOnFail":true,"typeVersion":3},{"id":"0aba0888-1491-4663-9129-9a105fdfc8dc","name":"Format Date For Youtube","type":"n8n-nodes-base.code","position":[340,1240],"parameters":{},"typeVersion":2},{"id":"85339928-b2cb-41e0-a76e-98dbe94243a2","name":"Sort","type":"n8n-nodes-base.sort","position":[-360,1240],"parameters":{},"typeVersion":1},{"id":"8eec23b5-0084-4cd1-a318-59bce571cc1c","name":"Limit","type":"n8n-nodes-base.limit","position":[-160,1240],"parameters":{},"typeVersion":1},{"id":"416d6c9b-6115-40b9-8952-71d21b38860e","name":"Message","type":"n8n-nodes-base.discord","position":[2840,1500],"webhookId":"f89fcd49-c854-4152-a346-4362a3adb8ee","parameters":{},"typeVersion":2},{"id":"5950c47d-41b3-449f-92ac-bde47f3883c7","name":"Message1","type":"n8n-nodes-base.discord","position":[-1060,1500],"webhookId":"f89fcd49-c854-4152-a346-4362a3adb8ee","parameters":{},"typeVersion":2},{"id":"8032a18b-b541-4385-a0c5-75ba0472ba5c","name":"Message2","type":"n8n-nodes-base.discord","position":[-100,-460],"webhookId":"f89fcd49-c854-4152-a346-4362a3adb8ee","parameters":{},"typeVersion":2},{"id":"abd1545c-4e4b-4ca9-b613-395332fdb7c8","name":"Message3","type":"n8n-nodes-base.discord","position":[3260,-380],"webhookId":"f89fcd49-c854-4152-a346-4362a3adb8ee","parameters":{},"typeVersion":2},{"id":"21f2c686-db86-4e60-aa88-c0856da239a4","name":"Message4","type":"n8n-nodes-base.discord","position":[5380,0],"webhookId":"f89fcd49-c854-4152-a346-4362a3adb8ee","parameters":{},"typeVersion":2},{"id":"343c43ba-a1ac-431a-ab25-1c68400e57f3","name":"Message5","type":"n8n-nodes-base.discord","disabled":true,"position":[-1520,-440],"webhookId":"f89fcd49-c854-4152-a346-4362a3adb8ee","parameters":{},"typeVersion":2},{"id":"1141de3b-d025-44c2-b18a-2adecd8350c8","name":"Execution Data6","type":"n8n-nodes-base.executionData","position":[2060,-460],"parameters":{},"typeVersion":1},{"id":"5ab32e2c-7e9f-4029-a749-9f0cb2cd4be9","name":"Log","type":"n8n-nodes-base.executionData","position":[-620,-40],"parameters":{},"typeVersion":1},{"id":"1e4802cf-e9a2-4c4c-abb7-7249483b0603","name":"Log2","type":"n8n-nodes-base.executionData","position":[-200,-80],"parameters":{},"typeVersion":1},{"id":"a92d19a5-91b5-4a49-8530-095b5999dae1","name":"Log1","type":"n8n-nodes-base.executionData","position":[3260,-40],"parameters":{},"typeVersion":1},{"id":"5db0a09c-689c-49ce-af72-98da7218c7b2","name":"Log3","type":"n8n-nodes-base.executionData","position":[5380,240],"parameters":{},"typeVersion":1},{"id":"f31b2a86-647a-4f3c-82f3-0dec88906987","name":"Log4","type":"n8n-nodes-base.executionData","position":[2840,1240],"parameters":{},"typeVersion":1},{"id":"6cca815f-e9b7-4869-a67a-aae1a218ca24","name":"Log5","type":"n8n-nodes-base.executionData","position":[1520,1040],"parameters":{},"typeVersion":1},{"id":"4fd9bc89-8627-49f2-b1cc-4e95484261bf","name":"Log6","type":"n8n-nodes-base.executionData","position":[-1060,1740],"parameters":{},"typeVersion":1},{"id":"71465e30-2939-4ffa-9c11-e4ab49d3dd6f","name":"Log7","type":"n8n-nodes-base.executionData","position":[4760,-180],"parameters":{},"typeVersion":1},{"id":"4f7333b7-d250-451d-9346-f0e8e82e56c8","name":"Log8","type":"n8n-nodes-base.executionData","position":[-2300,-40],"parameters":{},"typeVersion":1},{"id":"560f76f4-3231-4c72-94f4-5b1515a7f461","name":"Log9","type":"n8n-nodes-base.executionData","position":[640,1700],"parameters":{},"typeVersion":1},{"id":"ddd2e1b1-8bcb-400b-b2e1-4ba787c9dec7","name":"Format","type":"n8n-nodes-base.dateTime","position":[340,1500],"parameters":{},"typeVersion":2},{"id":"16fd3d57-dbf7-469a-a91c-d9284b2a67e4","name":"Reggae","type":"n8n-nodes-base.youTube","position":[2100,800],"parameters":{},"typeVersion":1},{"id":"2327383e-a4c4-495e-ab68-db57ab03abb9","name":"EDM","type":"n8n-nodes-base.youTube","position":[2100,1020],"parameters":{},"typeVersion":1},{"id":"bc5cf556-7041-406f-804b-eb815b5a1262","name":"Switch","type":"n8n-nodes-base.switch","position":[1740,1180],"parameters":{},"typeVersion":3.2},{"id":"a333f6ca-d411-4dbd-bc29-471b373b3284","name":"Determine Playlist","type":"n8n-nodes-base.code","position":[1520,1240],"parameters":{},"typeVersion":2},{"id":"87d0cc53-874d-4e1d-a9a4-a14b8541e901","name":"Format1","type":"n8n-nodes-base.dateTime","position":[-1680,-440],"parameters":{},"typeVersion":2},{"id":"2f61bf21-b057-4609-a118-d11c2fdca8ed","name":"Date & Time","type":"n8n-nodes-base.dateTime","position":[-1840,-440],"parameters":{},"typeVersion":2},{"id":"81481fe6-0bf2-49eb-ac3b-91441f7fab7d","name":"If2","type":"n8n-nodes-base.if","position":[80,1060],"parameters":{},"typeVersion":2.2},{"id":"37e589a7-d5b6-4ec2-95bf-691054d2e398","name":"Upload Video","type":"n8n-nodes-base.googleDrive","position":[5060,160],"parameters":{},"typeVersion":3},{"id":"67fe6ea2-b997-44d4-b4a8-b60b20677bd3","name":"Clean Title","type":"n8n-nodes-base.code","position":[-2100,-240],"parameters":{},"typeVersion":2},{"id":"fd701b34-097b-4813-a414-585226f3594a","name":"Keywords","type":"n8n-nodes-base.set","position":[-2300,-240],"parameters":{},"typeVersion":3.4},{"id":"1c17770d-3f20-4a4f-8c5d-0ae5adb1f63b","name":"Country","type":"n8n-nodes-base.youTube","position":[2100,1240],"parameters":{},"typeVersion":1},{"id":"e24b5d4c-8d2c-48d6-bd9b-712b4079f59e","name":"Pop","type":"n8n-nodes-base.youTube","position":[2100,1680],"parameters":{},"typeVersion":1},{"id":"b98603be-e1ff-4164-ad27-d533a822ddde","name":"Disco","type":"n8n-nodes-base.youTube","position":[2100,1460],"parameters":{},"typeVersion":1},{"id":"ca469366-8ea9-4518-97e3-c2aa8447cae6","name":"Truncate","type":"n8n-nodes-base.code","position":[-600,-460],"parameters":{},"typeVersion":2},{"id":"e21e702b-06a1-4de8-af7d-7fcdea524399","name":"Message6","type":"n8n-nodes-base.discord","position":[-440,-460],"webhookId":"f89fcd49-c854-4152-a346-4362a3adb8ee","parameters":{},"typeVersion":2},{"id":"ca724bb8-1e00-4be3-a52d-8ca852fe2cfa","name":"Extract Genre","type":"n8n-nodes-base.code","position":[-1840,-240],"parameters":{},"typeVersion":2},{"id":"dc5c47fa-f47f-47f5-8c15-af88105b8780","name":"Pop Style","type":"n8n-nodes-base.set","position":[800,60],"parameters":{},"typeVersion":3.4},{"id":"a27faedc-d633-4bbe-b504-f371234f2b85","name":"Genre Styles","type":"n8n-nodes-base.switch","position":[460,-300],"parameters":{},"typeVersion":3.2},{"id":"5d8cec56-8389-4fd0-9956-ab691b7029fc","name":"EDM Style","type":"n8n-nodes-base.set","position":[800,-540],"parameters":{},"typeVersion":3.4},{"id":"8c95bb90-e4c4-43e2-b291-cb8e6abccf1f","name":"Country Style","type":"n8n-nodes-base.set","position":[800,-340],"parameters":{},"typeVersion":3.4},{"id":"b0becb2a-88d4-426f-84ae-86e9653c60f1","name":"Disco Style","type":"n8n-nodes-base.set","position":[800,-140],"parameters":{},"typeVersion":3.4},{"id":"d52f574c-d47f-438e-a26f-51f46214fba9","name":"Reggae Style","type":"n8n-nodes-base.set","position":[800,-740],"parameters":{},"typeVersion":3.4},{"id":"6f0e1cd0-d8ce-4276-ad0b-ce0437efead1","name":"Random Style","type":"n8n-nodes-base.set","position":[800,280],"parameters":{},"typeVersion":3.4},{"id":"8c9de261-7f85-4812-897b-53841a301d00","name":"Set Style","type":"n8n-nodes-base.set","position":[1220,-220],"parameters":{},"typeVersion":3.4},{"id":"6a3d7aa7-2c69-489f-badd-4eb0c3cf5347","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-920,-600],"parameters":{"content":""},"typeVersion":1},{"id":"0ba4752c-0449-4240-a96e-66457bae4869","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[340,-880],"parameters":{"content":""},"typeVersion":1},{"id":"0c9a2935-215a-4bc8-960d-325b29ecaace","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[1520,-560],"parameters":{"content":""},"typeVersion":1},{"id":"f8bea771-2575-4c82-b867-86a2bfb8135a","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[3740,-460],"parameters":{"content":""},"typeVersion":1},{"id":"87678f0a-a8f1-4f5d-9228-0879bdf38bc3","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-660,920],"parameters":{"content":""},"typeVersion":1},{"id":"e84b4cba-4431-4004-8dcb-58ee0b281bee","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[1040,740],"parameters":{"content":""},"typeVersion":1},{"id":"34775b8c-87c2-4882-bf5b-583fda501996","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-1680,1100],"parameters":{"content":""},"typeVersion":1},{"id":"53a6a217-5087-4783-a802-7a379642f216","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[-2780,-560],"parameters":{"content":""},"typeVersion":1}],"active":true,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"e7c3f121-edd8-4059-aac2-59ae1c8a2a99","connections":{"If":{"main":[[{"node":"Delete Art","type":"main","index":0}],[{"node":"Cover Art","type":"main","index":0}]]},"Add":{"main":[[{"node":"Format Date For Youtube","type":"main","index":0},{"node":"Format","type":"main","index":0}]]},"EDM":{"main":[[{"node":"Update Row","type":"main","index":0}]]},"If1":{"main":[[{"node":"Delete Video","type":"main","index":0}],[{"node":"Combine Audio + Image","type":"main","index":0},{"node":"Log7","type":"main","index":0}]]},"Pop":{"main":[[{"node":"Update Row","type":"main","index":0}]]},"Log5":{"main":[[]]},"Log9":{"main":[[]]},"Sort":{"main":[[{"node":"Limit","type":"main","index":0}]]},"Tags":{"main":[[{"node":"Get Schedule","type":"main","index":0},{"node":"Message1","type":"main","index":0},{"node":"Log6","type":"main","index":0}]]},"Disco":{"main":[[{"node":"Update Row","type":"main","index":0}]]},"Limit":{"main":[[{"node":"Add","type":"main","index":0},{"node":"If2","type":"main","index":0}]]},"Format":{"main":[[{"node":"Log9","type":"main","index":0}]]},"Reggae":{"main":[[{"node":"Update Row","type":"main","index":0}]]},"Switch":{"main":[[{"node":"Reggae","type":"main","index":0}],[{"node":"EDM","type":"main","index":0}],[{"node":"Country","type":"main","index":0}],[{"node":"Disco","type":"main","index":0}],[{"node":"Pop","type":"main","index":0}],[{"node":"Update Row","type":"main","index":0}]]},"Upload":{"main":[[{"node":"Determine Playlist","type":"main","index":0},{"node":"Log5","type":"main","index":0}]]},"Country":{"main":[[{"node":"Update Row","type":"main","index":0}]]},"Format1":{"main":[[{"node":"Message5","type":"main","index":0}]]},"Keywords":{"main":[[{"node":"Clean Title","type":"main","index":0}]]},"Message5":{"main":[[]]},"Truncate":{"main":[[{"node":"Message6","type":"main","index":0}]]},"Cover Art":{"main":[[{"node":"Upload Art","type":"main","index":0}]]},"EDM Style":{"main":[[{"node":"Set Style","type":"main","index":0}]]},"Pop Style":{"main":[[{"node":"Set Style","type":"main","index":0}]]},"Set Style":{"main":[[{"node":"Image Prompt","type":"main","index":0}]]},"Delete Art":{"main":[[{"node":"Cover Art","type":"main","index":0}]]},"Search Art":{"main":[[{"node":"If","type":"main","index":0}]]},"Transcribe":{"main":[[{"node":"Description","type":"main","index":0},{"node":"Log","type":"main","index":0},{"node":"Truncate","type":"main","index":0}]]},"Update Row":{"main":[[{"node":"Log4","type":"main","index":0},{"node":"Message","type":"main","index":0}]]},"Upload Art":{"main":[[{"node":"Message3","type":"main","index":0},{"node":"Log1","type":"main","index":0},{"node":"Search Video","type":"main","index":0}]]},"Clean Title":{"main":[[{"node":"Extract Genre","type":"main","index":0},{"node":"Date & Time","type":"main","index":0}]]},"Date & Time":{"main":[[{"node":"Format1","type":"main","index":0}]]},"Description":{"main":[[{"node":"Message2","type":"main","index":0},{"node":"Log2","type":"main","index":0},{"node":"Genre Styles","type":"main","index":0}]]},"Disco Style":{"main":[[{"node":"Set Style","type":"main","index":0}]]},"Delete Video":{"main":[[{"node":"Combine Audio + Image","type":"main","index":0},{"node":"Log7","type":"main","index":0}]]},"Genre Styles":{"main":[[{"node":"Reggae Style","type":"main","index":0}],[{"node":"EDM Style","type":"main","index":0}],[{"node":"Country Style","type":"main","index":0}],[{"node":"Disco Style","type":"main","index":0}],[{"node":"Pop Style","type":"main","index":0}],[{"node":"Random Style","type":"main","index":0}]]},"Get Schedule":{"main":[[{"node":"Sort","type":"main","index":0}]]},"Image Prompt":{"main":[[{"node":"Search Art","type":"main","index":0},{"node":"Execution Data6","type":"main","index":0}]]},"Random Style":{"main":[[{"node":"Set Style","type":"main","index":0}]]},"Reggae Style":{"main":[[{"node":"Set Style","type":"main","index":0}]]},"Search Video":{"main":[[{"node":"If1","type":"main","index":0}]]},"Upload Video":{"main":[[{"node":"Message4","type":"main","index":0},{"node":"Log3","type":"main","index":0},{"node":"Tags","type":"main","index":0}]]},"Country Style":{"main":[[{"node":"Set Style","type":"main","index":0}]]},"Extract Genre":{"main":[[{"node":"Download Audio","type":"main","index":0}]]},"Download Audio":{"main":[[{"node":"Transcribe","type":"main","index":0}]]},"Download Video":{"main":[[{"node":"Upload","type":"main","index":0}]]},"Determine Playlist":{"main":[[{"node":"Switch","type":"main","index":0}]]},"Combine Audio + Image":{"main":[[{"node":"Upload Video","type":"main","index":0}]]},"Format Date For Youtube":{"main":[[{"node":"Download Video","type":"main","index":0}]]},"Watch New Song in Drive":{"main":[[{"node":"Log8","type":"main","index":0},{"node":"Keywords","type":"main","index":0}]]}}}


name: Automated Invoice Processing with Telegram, GPT-4o, OCR and SAP Integration
author_name: Raquel Giugliano
author_username: raquelgiugliano
categories: []
created_at: 2025-06-10T10:01:39.029Z
updated_at: 2025-06-10T10:01:39.029Z
url: https://n8n.io/workflows/4849
scraped_at: 2025-06-19 22:48:35
description:
  ++HOW IT WORKS:++
  This workflow automates the processing of invoices sent via Telegram. It extracts the data using LlamaIndex OCR, logs it in Google Sheets, and optionally pushes the structured data to SAP Business One

  🔹 1. Receive Invoice via Telegram:**
  A user sends a PDF of an invoice through Telegram
  A Telegram Trigger node listens for incoming messages and captures the file and metadata
  The document is downloaded and prepared for OCR

  🔹 2. OCR with LlamaIndex:
  The file is uploaded to the LlamaIndex OCR API.
  The workflow polls the API until the processing status returns SUCCESS
  Once ready, the parsed content is fetched in Markdown format

  🔹 3. Data Extraction via LLM (editable):
  The Markdown content is sent to a language model (LLM) using LangChain
  A Structured Output Parser transforms the result into a clean, structured editable JSON

  🔹 4. Save to Google Sheets:
  The structured JSON is split into:
  Header (main invoice metadata)
  Detail (individual line items)

  Each part is stored in a dedicated tab within a connected Google Sheets file

  🔹 5. Ask for SAP Confirmation:
  The bot replies to the user via Telegram:

  "Do you want to send the data to SAP?"

  If the user clicks "Yes", the next automation path is triggered.

  🔹 6. Push Data to SAP B1:
  A connection is made to SAP Business One's Service Layer API

  Header and detail data are fetched from Google Sheets

  The invoice structure is rebuilt as required by SAP (DocumentLines, CardCode, etc.)

  A POST request creates the Purchase Invoice in SAP

  A confirmation message with the created DocEntry is sent back to the user on Telegram

  ++SET UP STEPS:++
  Follow these steps to properly configure the workflow before execution:

  1️⃣ Create Required Credentials:
  Go to Credentials &gt; + New Credential and create the following:
  Telegram API (set your bot token get it from BotFather)
  Google Sheets
  OpenAI

  2️⃣ Set Up Environment Variables (Optional but Recommended):
  LLAMAINDEX_API_KEY
  SAP_USER
  SAP_PASSWORD
  SAP_COMPANY_DB
  SAP_URL

  3️⃣ Prepare Google Sheets:
  Ensure your Google Spreadsheet has the following:
  ➤ Sheet 1: Header
  ➤ Sheet 2: Details
  Contains columns for invoice lines

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

workflow_json:
  {"id":"5mGRqFpu73QguZPC","meta":{"instanceId":"06b3271522ae4bedcb94de9dac3219d19e1a4e5fcd0a448a4abc68198b391077","templateCredsSetupCompleted":true},"name":"ocr Telegram - SAP","tags":[],"nodes":[{"id":"026397ff-3b84-49f4-adf1-d4e8bef01e38","name":"Wait","type":"n8n-nodes-base.wait","position":[1620,100],"webhookId":"76b9bf12-3264-40e5-94dc-676f3954f41c","parameters":{"amount":3},"typeVersion":1.1},{"id":"7c032e9c-edc3-4b23-89d5-66e092b37857","name":"Basic LLM Chain","type":"@n8n/n8n-nodes-langchain.chainLlm","position":[1840,-100],"parameters":{"text":"={{ $json.markdown }}","batching":{},"messages":{"messageValues":[{"message":"Eres un asistente experto en extracción y procesamiento de datos de documentos especializado en identificar con precisión los detalles claves de una factura"},{"type":"HumanMessagePromptTemplate","message":"=Tu tarea: Extraer de cualquier texto de factura los siguientes campos, devolviendo los datos en un JSON estructurado y con máxima precisión:\n\nCampos a extraer:\nnombre_proveedor: Nombre del proveedor.\n\nruc_proveedor: RUC del proveedor.\n\ndireccion_proveedor: Dirección del proveedor.\n\nnumero_factura: Número de factura.\n\nfecha_emision: Fecha de emisión de la factura (formato YYYY-MM-DD).\n\ndetalle_productos: Lista de líneas de detalle de los productos o servicios facturados. Cada línea incluirá:\n\ncodigo\n\ndescripcion\n\ncantidad\n\nprecio\n\nsubtotal\n\nsubtotal_factura: Subtotal general de la factura.\n\ndescuento_factura: Descuento total de la factura.\n\ntotal_neto: Total neto de la factura.\n\nFormato de salida esperado:\nSi algún campo no existe, deberá devolverse como null.\nDevuelve siempre el JSON con los nombres exactos de las claves.\n\nEjemplo de salida esperado:\n\n{\n  \"nombre_proveedor\": \"Blockies Corporation\",\n  \"ruc_proveedor\": \"78787878-7\",\n  \"direccion_proveedor\": \"AV. DE LAS ARTES NORTE NRO. 310 (ESPALDA RAMBLA DE JAVIER PRADO) LIMA - LIMA - SAN BORJA\",\n  \"numero_factura\": \"00003\",\n  \"fecha_emision\": \"2025-04-15\",\n  \"detalle_productos\": [\n    {\n      \"codigo\": \"srv001\",\n      \"descripcion\": \"Servicio de Alquiler de Montacargas\",\n      \"cantidad\": 1,\n      \"precio\": 35.00,\n      \"subtotal\": 35.00\n    }\n  ],\n  \"subtotal_factura\": 35.00,\n  \"descuento_factura\": 0.00,\n  \"total_neto\": 35.00\n}\nInstrucciones adicionales:\nNo resumas, no expliques, no añadas comentarios, solo responde con el JSON.\n\nSi existen varias líneas de productos, incluir todas dentro del array \"detalle_productos\".\n\nNo redondees importes, extrae exactamente el valor mostrado.\n\nLas fechas deben estar siempre en formato YYYY-MM-DD."}]},"promptType":"define","hasOutputParser":true},"typeVersion":1.7},{"id":"036c0443-0224-4a2f-9a9a-c7d9feebbdc3","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[1840,80],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"typeVersion":1.2},{"id":"0af0d3fb-6b87-44b4-8fe8-3c992c74a10d","name":"No Operation, do nothing","type":"n8n-nodes-base.noOp","position":[760,820],"parameters":{},"typeVersion":1},{"id":"a9201f0b-e504-45c2-ade0-86004ba5e323","name":"Split Out","type":"n8n-nodes-base.splitOut","position":[2280,-100],"parameters":{"options":{},"fieldToSplitOut":"output.detalle_productos"},"typeVersion":1},{"id":"8a189ae2-64d4-459b-a8fd-81b4423cf135","name":"Merge","type":"n8n-nodes-base.merge","position":[2240,540],"parameters":{"mode":"combine","options":{},"combineBy":"combineByPosition"},"typeVersion":3.2},{"id":"b13a0de4-a00e-4b38-8b12-fa9c2b1825d9","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-140,460],"parameters":{"width":3720,"height":560,"content":"## Waiting for an answer on telegram"},"typeVersion":1},{"id":"4aa3c30a-4a2c-4168-866d-4e1b8a3651f5","name":"Callback Waiting Answer","type":"n8n-nodes-base.telegramTrigger","position":[-40,640],"webhookId":"56b0ca20-2362-4658-b2b8-692b0303ae0c","parameters":{"updates":["callback_query"],"additionalFields":{}},"credentials":{"telegramApi":{"id":"d7ed9EHZ1GiHews4","name":"Telegram account"}},"typeVersion":1.2},{"id":"8b49790e-fc03-4a1b-944c-139e383a0a46","name":"Answer?","type":"n8n-nodes-base.switch","position":[300,640],"parameters":{"rules":{"values":[{"outputKey":"SI","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"c3ae2bff-a96d-4f42-b0b3-e04f8ef372d1","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.callback_query.data }}","rightValue":"respuesta_si"}]},"renameOutput":true},{"outputKey":"NO","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"59ccf0b4-bb12-4c10-b289-354be138f96c","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.callback_query.data }}","rightValue":"respuesta_no"}]},"renameOutput":true}]},"options":{}},"typeVersion":3.2},{"id":"a958d830-0608-4d9b-a14d-922869c9fbd3","name":"Connect to SAP","type":"n8n-nodes-base.httpRequest","position":[760,520],"parameters":{"url":"={{ $vars.url_sap }}Login","method":"POST","options":{"allowUnauthorizedCerts":true},"jsonBody":"={\n       \"UserName\": \"{{ $vars.user_sap }}\",\n       \"Password\": \"{{ $vars.password_sap }}\",\n       \"CompanyDB\": \"{{ $vars.company_db }}\"\n}","sendBody":true,"specifyBody":"json"},"typeVersion":4.2,"alwaysOutputData":false},{"id":"ec4c8074-6aa8-4f89-812c-3d6305a10d60","name":"Get Header","type":"n8n-nodes-base.googleSheets","position":[1160,520],"parameters":{"sheetName":{"__rl":true,"mode":"list","value":"","cachedResultUrl":"","cachedResultName":""},"documentId":{"__rl":true,"mode":"list","value":""}},"credentials":{"googleSheetsOAuth2Api":{"id":"dWCmToHbrXSRjlDB","name":"Google Sheets account"}},"typeVersion":4.6},{"id":"5e290a19-236a-4baa-9093-1b32f486b058","name":"Get Row Details","type":"n8n-nodes-base.googleSheets","position":[1560,680],"parameters":{"sheetName":{"__rl":true,"mode":"list","value":"","cachedResultUrl":"","cachedResultName":""},"documentId":{"__rl":true,"mode":"list","value":""}},"credentials":{"googleSheetsOAuth2Api":{"id":"dWCmToHbrXSRjlDB","name":"Google Sheets account"}},"typeVersion":4.6,"alwaysOutputData":false},{"id":"42edf631-ee30-4b6f-b10b-fa53ee148c26","name":"Generate DocumentLines","type":"n8n-nodes-base.code","position":[1880,680],"parameters":{"jsCode":"const items = $input.all();  // capturamos todos los items que entran\nconst DocumentLines = [];\n\nfor (let i = 0; i < items.length; i++) {\n  const item = items[i].json;\n\n  DocumentLines.push({\n    ItemCode: item.código,\n    Quantity: item.cantidad,\n    UnitPrice: item.precio\n  });\n}\n\nreturn [{ DocumentLines }];\n"},"typeVersion":2},{"id":"d9d54a86-50e7-469a-88a2-c5860459bf99","name":"Create JSON","type":"n8n-nodes-base.code","position":[2580,540],"parameters":{"jsCode":"const item = $json;\n\n// Construimos el objeto final para SAP\nreturn [{\n  DocDate: item.fecha_emision,\n  DocDueDate: item.fecha_emision,\n  CardCode: item.ruc_proveedor,\n  DocumentLines: item.DocumentLines\n}];"},"typeVersion":2},{"id":"dfbd5b4b-a545-4062-bfdb-1d383c8277f6","name":"POST PurchaseInvoices","type":"n8n-nodes-base.httpRequest","position":[2980,540],"parameters":{"url":"={{ $vars.url_sap }}PurchaseInvoices","body":"={{ JSON.stringify($json) }}","method":"POST","options":{"allowUnauthorizedCerts":true},"sendBody":true,"contentType":"raw","sendHeaders":true,"rawContentType":"application/json","headerParameters":{"parameters":[{"name":"Cookie","value":"=B1SESSION={{ $('Connect to SAP').item.json.SessionId }}"}]}},"typeVersion":4.2},{"id":"ec33a3bf-2632-4f49-b0c8-4fe1284c90df","name":"PurchaseInvoices created","type":"n8n-nodes-base.telegram","position":[3360,540],"webhookId":"a3f4bedb-06da-446e-8a1a-a2666b511152","parameters":{"text":"=PurchaseInvoice {{ $json.DocEntry }} creada en SAP correctamente","chatId":"={{ $('Callback Waiting Answer').item.json.callback_query.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"d7ed9EHZ1GiHews4","name":"Telegram account"}},"typeVersion":1.2},{"id":"311d3616-3ebf-439f-8d6f-f5aa18e89bc6","name":"Trigger Receive Message","type":"n8n-nodes-base.telegramTrigger","position":[0,0],"webhookId":"5af23994-f45e-4b53-8bc0-edfee56e962c","parameters":{"updates":["message"],"additionalFields":{}},"typeVersion":1.2},{"id":"c01eb2e3-7aa8-4a4c-897f-4414816fa459","name":"Capture Telegram Data","type":"n8n-nodes-base.set","position":[260,0],"parameters":{"options":{},"assignments":{"assignments":[{"id":"b6e43e6c-452f-4747-b17c-2de6191fb0f0","name":"message.chat.id","type":"number","value":"={{ $json.message.chat.id }}"},{"id":"a82f3829-5ce1-4a94-b7e0-a1449f7a3da6","name":"message.chat","type":"object","value":"={{ $json.message.chat }}"},{"id":"619ffe10-2bea-4bda-a356-501562628bc5","name":"telegram.file_id","type":"string","value":"={{ $json.message.document.file_id }}"},{"id":"afbbdb8a-47e8-4b33-8f81-91989d1121af","name":"message.caption","type":"string","value":"={{ $('Trigger Receive Message').item.json.message.caption }}"}]}},"typeVersion":3.4},{"id":"bacef005-e65c-4894-aa0b-8ef34033daac","name":"File Received","type":"n8n-nodes-base.telegram","position":[500,0],"webhookId":"39a7a3e0-95ba-400f-9c3b-58bfc70b5fb3","parameters":{"text":"Hemos recibido tu documento y lo estamos procesando...","chatId":"={{ $json.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"d7ed9EHZ1GiHews4","name":"Telegram account"}},"typeVersion":1.2},{"id":"01bae880-e0d1-449f-b459-94b7a56b3adb","name":"Download File","type":"n8n-nodes-base.telegram","position":[720,0],"webhookId":"1393ba90-f818-4d06-88b9-806d1542abea","parameters":{"fileId":"={{ $('Capture Telegram Data').item.json.telegram.file_id }}","resource":"file"},"credentials":{"telegramApi":{"id":"d7ed9EHZ1GiHews4","name":"Telegram account"}},"typeVersion":1.2},{"id":"86e1b80a-302d-4010-a740-ce916f8f74df","name":"Upload File LlamaIndex","type":"n8n-nodes-base.httpRequest","position":[940,0],"parameters":{"url":"https://api.cloud.llamaindex.ai/api/v1/parsing/upload","method":"POST","options":{},"sendBody":true,"contentType":"multipart-form-data","sendHeaders":true,"bodyParameters":{"parameters":[{"name":"file","parameterType":"formBinaryData","inputDataFieldName":"data"}]},"headerParameters":{"parameters":[{"name":"accept","value":"application/json"},{"name":"Authorization","value":"=Bearer {{ $vars.llamaindex_apikey }}"}]}},"typeVersion":4.2},{"id":"92f93bbd-3192-40aa-b81f-bf5165e3dc35","name":"Validate Status LlamaIndex","type":"n8n-nodes-base.httpRequest","position":[1180,0],"parameters":{"url":"=https://api.cloud.llamaindex.ai/api/v1/parsing/job/{{ $json.id }}","options":{},"sendHeaders":true,"headerParameters":{"parameters":[{"name":"accept","value":"application/json"},{"name":"Authorization","value":"=Bearer {{ $vars.llamaindex_apikey }}"}]}},"typeVersion":4.2},{"id":"4914e5d3-ec4e-4c96-b6c1-6f2ede2b5b38","name":"Status?","type":"n8n-nodes-base.switch","position":[1400,0],"parameters":{"rules":{"values":[{"outputKey":"SUCCESS","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"7005abbb-4094-4dde-9cc5-b973fe54a09e","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.status }}","rightValue":"SUCCESS"}]},"renameOutput":true},{"outputKey":"PENDING","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"b4bdda84-6e9d-44c9-a85c-fd87d7427765","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.status }}","rightValue":"PENDING"}]},"renameOutput":true}]},"options":{}},"typeVersion":3.2},{"id":"d2c19099-01c7-4547-aa3e-944c16009aaf","name":"Get Results LlamaIndex","type":"n8n-nodes-base.httpRequest","position":[1620,-100],"parameters":{"url":"=https://api.cloud.llamaindex.ai/api/v1/parsing/job/{{ $json.id }}/result/markdown","options":{},"sendHeaders":true,"headerParameters":{"parameters":[{"name":"accept","value":"application/json"},{"name":"Authorization","value":"=Bearer {{ $vars.llamaindex_apikey }}"}]}},"typeVersion":4.2},{"id":"c0ba5071-56b6-45c0-b0ad-bb87b8c543ca","name":"Structured Output Parser (Example)","type":"@n8n/n8n-nodes-langchain.outputParserStructured","position":[2060,60],"parameters":{"jsonSchemaExample":"{\n  \"nombre_proveedor\": \"Blockies Corporation\",\n  \"ruc_proveedor\": \"78787878-7\",\n  \"direccion_proveedor\": \"AV. DE LAS ARTES NORTE NRO. 310 (ESPALDA RAMBLA DE JAVIER PRADO) LIMA - LIMA - SAN BORJA\",\n  \"numero_factura\": \"00003\",\n  \"fecha_emision\": \"2025-04-15\",\n  \"detalle_productos\": [\n    {\n      \"codigo\": \"srv001\",\n      \"descripcion\": \"Servicio de Alquiler de Montacargas\",\n      \"cantidad\": 1,\n      \"precio\": 35.00,\n      \"subtotal\": 35.00\n    }\n  ],\n  \"subtotal_factura\": 35.00,\n  \"descuento_factura\": 0.00,\n  \"total_neto\": 35.00\n}"},"typeVersion":1.2},{"id":"f62a9650-a966-4efa-a9ec-ee166e4e3881","name":"Detail","type":"n8n-nodes-base.googleSheets","position":[2480,80],"parameters":{"columns":{"value":{"precio":"={{ $('Split Out').item.json.precio }}","código":"={{ $('Split Out').item.json.codigo }}","cantidad":"={{ $('Split Out').item.json.cantidad }}","subtotal":"={{ $('Split Out').item.json.subtotal }}","descripcion":"={{ $('Split Out').item.json.descripcion }}","numero_factura":"={{ $('Basic LLM Chain').item.json.output.numero_factura }}"},"schema":[{"id":"numero_factura","type":"string","display":true,"required":false,"displayName":"numero_factura","defaultMatch":false,"canBeUsedToMatch":true},{"id":"código","type":"string","display":true,"required":false,"displayName":"código","defaultMatch":false,"canBeUsedToMatch":true},{"id":"descripcion","type":"string","display":true,"required":false,"displayName":"descripcion","defaultMatch":false,"canBeUsedToMatch":true},{"id":"cantidad","type":"string","display":true,"required":false,"displayName":"cantidad","defaultMatch":false,"canBeUsedToMatch":true},{"id":"precio","type":"string","display":true,"required":false,"displayName":"precio","defaultMatch":false,"canBeUsedToMatch":true},{"id":"subtotal","type":"string","display":true,"required":false,"displayName":"subtotal","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","documentId":{"__rl":true,"mode":"list","value":""}},"typeVersion":4.6},{"id":"ec718e9d-d729-4493-8439-78cf63394e28","name":"Header","type":"n8n-nodes-base.googleSheets","position":[2620,-100],"parameters":{"operation":"append","sheetName":{"__rl":true,"mode":"list","value":""},"documentId":{"__rl":true,"mode":"list","value":""}},"credentials":{"googleSheetsOAuth2Api":{"id":"dWCmToHbrXSRjlDB","name":"Google Sheets account"}},"executeOnce":true,"typeVersion":4.6},{"id":"d30ac579-8f31-471f-89d6-e27b6b99a4f3","name":"¿Upload to SAP?","type":"n8n-nodes-base.telegram","position":[2900,-100],"webhookId":"f327fe60-a943-4b8b-8413-8caf56d4657d","parameters":{"text":"=¿Quieres enviar los datos a SAP?","chatId":"={{ $('Capture Telegram Data').item.json.message.chat.id }}","replyMarkup":"inlineKeyboard","inlineKeyboard":{"rows":[{"row":{"buttons":[{"text":"Si","additionalFields":{"callback_data":"respuesta_si"}},{"text":"No","additionalFields":{"callback_data":"respuesta_no"}}]}}]},"additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"d7ed9EHZ1GiHews4","name":"Telegram account"}},"executeOnce":true,"typeVersion":1.2},{"id":"e80fa814-502a-4af1-8c3f-8b35c65ed0eb","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-120,-180],"parameters":{"color":7,"width":3280,"height":540,"content":"## Send data and OCR with LlamaIndex\n"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"c7b1fdbb-20e4-48aa-b67a-7da7ceee2fa7","connections":{"Wait":{"main":[[{"node":"Validate Status LlamaIndex","type":"main","index":0}]]},"Merge":{"main":[[{"node":"Create JSON","type":"main","index":0}]]},"Detail":{"main":[[{"node":"Header","type":"main","index":0}]]},"Header":{"main":[[{"node":"¿Upload to SAP?","type":"main","index":0}]]},"Answer?":{"main":[[{"node":"Connect to SAP","type":"main","index":0}],[{"node":"No Operation, do nothing","type":"main","index":0}]]},"Status?":{"main":[[{"node":"Get Results LlamaIndex","type":"main","index":0}],[{"node":"Wait","type":"main","index":0}]]},"Split Out":{"main":[[{"node":"Detail","type":"main","index":0}]]},"Get Header":{"main":[[{"node":"Get Row Details","type":"main","index":0},{"node":"Merge","type":"main","index":0}]]},"Create JSON":{"main":[[{"node":"POST PurchaseInvoices","type":"main","index":0}]]},"Download File":{"main":[[{"node":"Upload File LlamaIndex","type":"main","index":0}]]},"File Received":{"main":[[{"node":"Download File","type":"main","index":0}]]},"Connect to SAP":{"main":[[{"node":"Get Header","type":"main","index":0}]]},"Basic LLM Chain":{"main":[[{"node":"Split Out","type":"main","index":0}]]},"Get Row Details":{"main":[[{"node":"Generate DocumentLines","type":"main","index":0}]]},"¿Upload to SAP?":{"main":[[]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Basic LLM Chain","type":"ai_languageModel","index":0}]]},"Capture Telegram Data":{"main":[[{"node":"File Received","type":"main","index":0}]]},"POST PurchaseInvoices":{"main":[[{"node":"PurchaseInvoices created","type":"main","index":0}]]},"Generate DocumentLines":{"main":[[{"node":"Merge","type":"main","index":1}]]},"Get Results LlamaIndex":{"main":[[{"node":"Basic LLM Chain","type":"main","index":0}]]},"Upload File LlamaIndex":{"main":[[{"node":"Validate Status LlamaIndex","type":"main","index":0}]]},"Callback Waiting Answer":{"main":[[{"node":"Answer?","type":"main","index":0}]]},"Trigger Receive Message":{"main":[[{"node":"Capture Telegram Data","type":"main","index":0}]]},"Validate Status LlamaIndex":{"main":[[{"node":"Status?","type":"main","index":0}]]},"Structured Output Parser (Example)":{"ai_outputParser":[[{"node":"Basic LLM Chain","type":"ai_outputParser","index":0}]]}}}


name: Export Cloudflare Domains with DNS Records and Settings to Google Sheets
author_name: KPendic
author_username: kres
nodes_used: ["n8n-nodes-base.googleSheets","n8n-nodes-base.httpRequest","n8n-nodes-base.code"]
categories: []
created_at: 2025-06-10T10:26:19.793Z
updated_at: 2025-06-10T10:26:19.793Z
url: https://n8n.io/workflows/4850
scraped_at: 2025-06-19 22:50:00
description:
  How it works

  This workflow simply exports all your CloudFlare domains to Google Sheet to get high overview of all of your settings. This could help for easy debugging, searching or similar needs. 
  In flow simple pagging nodes are used to iterate over all your domains, because this list could be huge. 
  For each host we are merging DNS & Settings and transforming them into columns for all our domains.

  Requirements

  For storing and processing of data in this flow you will need:

  CloudFlare.com API key/token - for retrieving your data (https://dash.cloudflare.com/:account/api-tokens) (need full access)
  Google Spreadsheet auth connected in your n8n Credentials
  Google Spreadsheet template - you can copy my sheet as starting point, start by copying it to your account 
  Match Sheet ID in 'Export' node to your newly created.

  Official CloudFlare api Documentation
  For full details and specifications please use API documentation from: https://developers.cloudflare.com/api/

  Potential API timeouts
  If you encounter CF API timeouts - I would suggest to only put somewhere in the loop simple sleep/wait node - for couple of seconds - and it should resolve timeouts.

  Google Sheet
  I've used simple Google Sheet feature conditional formatting to visually distinct my on|off toggles that was of my interest to easily get high overview for debuggint some of the settings on my hosts - but please use your own logic or change it completely.

workflow_json:
  {"meta":{"instanceId":"fe41feb5409a7d5eb53f7743740840b086b13d9f15b9a1b3a5f34f2bb43129c3","templateCredsSetupCompleted":true},"nodes":[{"id":"9fd3e8a6-291f-4aba-bdc2-9055bd0e6d6b","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[680,380],"parameters":{"color":7,"width":500,"height":240,"content":"# Requirements\n\nFor storing and processing of data in this flow you will need:\n\n- CloudFlare.com API key/token - for retrieving your data (https://dash.cloudflare.com/:account/api-tokens) (need full access)\n- Google Spreadsheet auth connected\n- Copy [my sheet](https://docs.google.com/spreadsheets/d/1jt6od8FMt-Yo7A_CPGuyfqWzL7HJk6SZmQQFO6kkWBo/edit?usp=sharing) as template to your account and match ID in 'Export' node to your newly created."},"typeVersion":1},{"id":"f4b9ee64-9c52-43bb-a91e-ad03a6286e3c","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[680,640],"parameters":{"color":7,"width":500,"height":600,"content":"# Author\n![Kpendic](https://gravatar.com/avatar/8e343ec0d9b4fb672f921e822a8561be?size=188)\n### Kresimir Pendic\nSenior BE professional, specializing in automation, AI and data analysis. \n\n## Say hi!\nhttps://www.linkedin.com/in/mkdizajn/\n\n\n### Video overview\nhttps://youtu.be/sW85-AxMp6g\n\n## Check out my other templates\n### 👉 https://n8n.io/creators/kres/\n"},"typeVersion":1},{"id":"b47eb629-9241-420c-8490-669d3ee1b037","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[680,1260],"parameters":{"width":500,"height":140,"content":"# Need help?\nFor getting help with this workflow, please create a topic on the community forums here:\nhttps://community.n8n.io/c/questions/"},"typeVersion":1},{"id":"00f46c50-55a1-48f8-a519-621973f2a886","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[680,220],"parameters":{"color":4,"width":2000,"height":140,"content":""},"typeVersion":1},{"id":"b5f368ea-72ae-4cb0-b09b-e80b9818f779","name":"Sticky Note9","type":"n8n-nodes-base.stickyNote","position":[1300,260],"parameters":{"color":4,"width":740,"height":80,"content":"# CloudFlare dump => Google Sheets"},"typeVersion":1},{"id":"2536518c-90b5-49be-8a22-0b3e542831f1","name":"When clicking ‘Test workflow’","type":"n8n-nodes-base.manualTrigger","position":[1280,600],"parameters":{},"typeVersion":1},{"id":"e206aea7-d544-43c2-89cd-9808ec164b03","name":"Note4","type":"n8n-nodes-base.stickyNote","position":[1200,380],"parameters":{"color":5,"width":1480,"height":920,"content":"## Fetch TLDs, each dns & settings & Transform data\n\n1. Get your CloudFlare domains and basic info\nhttps://dash.cloudflare.com/:account/api-tokens\n2. Adapt your Transformings to your specific needs\n3. Easily expand to add your custom endpoints - follow CloudFlare api docs:\nhttps://developers.cloudflare.com/api/"},"typeVersion":1},{"id":"fa2397fa-baee-4aca-8ca3-8c0d1d2fada4","name":"Wait","type":"n8n-nodes-base.wait","position":[1380,1020],"webhookId":"34f21572-31a2-4c5b-a08a-d4be2e33651d","parameters":{"amount":0.3},"typeVersion":1.1},{"id":"da801aa4-e3f1-4e56-93e4-928eda0962d5","name":"Set Page","type":"n8n-nodes-base.set","position":[1520,600],"parameters":{"values":{"number":[{"name":"page","value":"={{$json[\"next_page\"] || 1}}"}]},"options":{},"keepOnlySet":true},"executeOnce":true,"typeVersion":1},{"id":"5ae6a35b-5090-449f-a689-b82a13ced8b3","name":"Increment Page","type":"n8n-nodes-base.set","position":[1280,820],"parameters":{"values":{"number":[{"name":"next_page","value":"={{ $('Set Page').first().json.page+1 }}"}]},"options":{}},"typeVersion":1},{"id":"deb40a37-4e32-4dc6-8620-8322ef8014ea","name":"More Pages?","type":"n8n-nodes-base.if","position":[1840,1080],"parameters":{"conditions":{"number":[{"value1":"={{ $('Set Page').first().json.page }}","value2":"={{ $('Get TLDs').first().json.result_info.total_pages }}"}]}},"executeOnce":false,"typeVersion":1},{"id":"fcd860d3-021e-4cb1-a347-ffbe1d61a184","name":"Merge","type":"n8n-nodes-base.merge","position":[1620,820],"parameters":{"mode":"combine","options":{},"combineBy":"combineByPosition","numberInputs":3},"executeOnce":false,"typeVersion":3.1},{"id":"2348687c-8ce7-440a-9209-7ddc39c046ca","name":"Get TLDs","type":"n8n-nodes-base.httpRequest","position":[1720,600],"parameters":{"url":"https://api.cloudflare.com/client/v4/zones","options":{},"sendQuery":true,"authentication":"genericCredentialType","genericAuthType":"httpCustomAuth","queryParameters":{"parameters":[{"name":"page","value":"={{ $json.page }}"}]}},"credentials":{"httpCustomAuth":{"id":"6l2hwj0eyB10vHc2","name":"CloudFlare headers"}},"executeOnce":true,"typeVersion":4.1},{"id":"542fad7f-13d5-4ddd-8558-23858b62764e","name":"Each Host","type":"n8n-nodes-base.splitOut","position":[1900,600],"parameters":{"options":{},"fieldToSplitOut":"result"},"executeOnce":false,"typeVersion":1},{"id":"0e2582e1-c058-4b18-a062-7f199beb56ef","name":"Get DNS","type":"n8n-nodes-base.httpRequest","position":[2160,760],"parameters":{"url":"=https://api.cloudflare.com/client/v4/zones/{{ $json.id }}/dns_records","options":{},"authentication":"genericCredentialType","genericAuthType":"httpCustomAuth"},"credentials":{"httpCustomAuth":{"id":"6l2hwj0eyB10vHc2","name":"CloudFlare headers"}},"typeVersion":4.1},{"id":"09d1c96b-dc94-43bd-8847-5ba40747747a","name":"Get Settings","type":"n8n-nodes-base.httpRequest","position":[2180,540],"parameters":{"url":"=https://api.cloudflare.com/client/v4/zones/{{ $json.id }}/settings","options":{},"authentication":"genericCredentialType","genericAuthType":"httpCustomAuth"},"credentials":{"httpCustomAuth":{"id":"6l2hwj0eyB10vHc2","name":"CloudFlare headers"}},"typeVersion":4.1},{"id":"12cf6091-df4b-4f8a-be93-79933778f667","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[2120,1000],"parameters":{"color":3,"width":540,"height":280,"content":"## 2. Add credentials for Google Sheets & save"},"typeVersion":1},{"id":"57f125f5-319c-4607-b3ed-522ee9d086c2","name":"Flatten","type":"n8n-nodes-base.code","position":[2240,1080],"parameters":{"jsCode":"\nfunction flatten(obj, prefix = '', res = {}) {\n  for (const key in obj) {\n    const value = obj[key];\n    const prefixedKey = prefix ? `${prefix}_${key}` : key;\n    \n    if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n      flatten(value, prefixedKey, res);\n    } else {\n      if (prefixedKey === \"json_records\") {\n        // Format DNS records: type + name + content\n        const formattedRecords = value\n          .map(record => `${record.type} ${record.name} ${record.content}`)\n          .join('\\n');\n        res[prefixedKey] = formattedRecords;\n        continue;\n      }\n      \n      if (prefixedKey === \"json_resultSETT\") {\n        // For each setting in the array, create a new column with setting.id as key\n        value.forEach(setting => {\n          res[setting.id] = setting.value;\n        });\n        continue;\n      }\n      \n      res[prefixedKey] = value;\n    }\n  }\n  return res;\n}\n\nreturn $input.all().map(item => ({\n  json: flatten(item)\n}));"},"typeVersion":2},{"id":"3c84495b-1c2d-4252-bb9e-6f77d009a660","name":"Filter TLD","type":"n8n-nodes-base.code","position":[1840,820],"parameters":{"jsCode":"// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nfor (const item of $input.all()) {\n  let validKeys = [ 'id', 'name', 'paused', 'name_servers' ];\n  Object.keys(item.json).forEach((key) => validKeys.includes(key) || delete item.json[key]);\n}\n\nreturn $input.all();"},"typeVersion":2},{"id":"d57e934d-d000-401f-938a-f9eeed756ff2","name":"Filter DNS","type":"n8n-nodes-base.code","position":[2400,800],"parameters":{"jsCode":"for (const item of $input.all()) {\n  // Extract the result array and clean up the DNS records\n  const dnsRecords = item.json.result;\n  \n  // Clean up each DNS record\n  for (let dnn of dnsRecords) {\n    let validKeys = ['type', 'content', 'name'];\n    Object.keys(dnn).forEach((key) => validKeys.includes(key) || delete dnn[key]);\n  }\n  \n  // Replace the item's json with a new object containing the array\n  item.json = {\n    records: dnsRecords\n  };\n}\n\nreturn $input.all();"},"typeVersion":2},{"id":"820d2a47-77c6-47bb-a236-9f91351ad343","name":"Filter Settings","type":"n8n-nodes-base.code","position":[2440,560],"parameters":{"jsCode":"// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nfor (const item of $input.all()) {\n  item.json.resultSETT = item.json.result;\n  delete item.json.result;\n  delete item.json.success;\n  delete item.json.errors;\n  delete item.json.messages;\n}\n\nreturn $input.all();"},"typeVersion":2},{"id":"c5cb1263-7b24-48be-9af4-25eba131db17","name":"Export","type":"n8n-nodes-base.googleSheets","position":[2460,1080],"parameters":{"columns":{"value":{},"schema":[{"id":"json_id","type":"string","display":true,"required":false,"displayName":"json_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"json_domain","type":"string","display":true,"required":false,"displayName":"json_domain","defaultMatch":false,"canBeUsedToMatch":true},{"id":"json_paused","type":"string","display":true,"required":false,"displayName":"json_paused","defaultMatch":false,"canBeUsedToMatch":true},{"id":"json_name_servers","type":"string","display":true,"required":false,"displayName":"json_name_servers","defaultMatch":false,"canBeUsedToMatch":true},{"id":"0rtt","type":"string","display":true,"required":false,"displayName":"0rtt","defaultMatch":false,"canBeUsedToMatch":true},{"id":"advanced_ddos","type":"string","display":true,"required":false,"displayName":"advanced_ddos","defaultMatch":false,"canBeUsedToMatch":true},{"id":"always_online","type":"string","display":true,"required":false,"displayName":"always_online","defaultMatch":false,"canBeUsedToMatch":true},{"id":"always_use_https","type":"string","display":true,"required":false,"displayName":"always_use_https","defaultMatch":false,"canBeUsedToMatch":true},{"id":"automatic_https_rewrites","type":"string","display":true,"required":false,"displayName":"automatic_https_rewrites","defaultMatch":false,"canBeUsedToMatch":true},{"id":"brotli","type":"string","display":true,"required":false,"displayName":"brotli","defaultMatch":false,"canBeUsedToMatch":true},{"id":"browser_cache_ttl","type":"string","display":true,"required":false,"displayName":"browser_cache_ttl","defaultMatch":false,"canBeUsedToMatch":true},{"id":"browser_check","type":"string","display":true,"required":false,"displayName":"browser_check","defaultMatch":false,"canBeUsedToMatch":true},{"id":"cache_level","type":"string","display":true,"required":false,"displayName":"cache_level","defaultMatch":false,"canBeUsedToMatch":true},{"id":"challenge_ttl","type":"string","display":true,"required":false,"displayName":"challenge_ttl","defaultMatch":false,"canBeUsedToMatch":true},{"id":"ciphers","type":"string","display":true,"required":false,"displayName":"ciphers","defaultMatch":false,"canBeUsedToMatch":true},{"id":"cname_flattening","type":"string","display":true,"required":false,"displayName":"cname_flattening","defaultMatch":false,"canBeUsedToMatch":true},{"id":"development_mode","type":"string","display":true,"required":false,"displayName":"development_mode","defaultMatch":false,"canBeUsedToMatch":true},{"id":"early_hints","type":"string","display":true,"required":false,"displayName":"early_hints","defaultMatch":false,"canBeUsedToMatch":true},{"id":"edge_cache_ttl","type":"string","display":true,"required":false,"displayName":"edge_cache_ttl","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_obfuscation","type":"string","display":true,"required":false,"displayName":"email_obfuscation","defaultMatch":false,"canBeUsedToMatch":true},{"id":"filter_logs_to_cloudflare","type":"string","display":true,"required":false,"displayName":"filter_logs_to_cloudflare","defaultMatch":false,"canBeUsedToMatch":true},{"id":"hotlink_protection","type":"string","display":true,"required":false,"displayName":"hotlink_protection","defaultMatch":false,"canBeUsedToMatch":true},{"id":"http2","type":"string","display":true,"required":false,"displayName":"http2","defaultMatch":false,"canBeUsedToMatch":true},{"id":"http3","type":"string","display":true,"required":false,"displayName":"http3","defaultMatch":false,"canBeUsedToMatch":true},{"id":"ip_geolocation","type":"string","display":true,"required":false,"displayName":"ip_geolocation","defaultMatch":false,"canBeUsedToMatch":true},{"id":"ipv6","type":"string","display":true,"required":false,"displayName":"ipv6","defaultMatch":false,"canBeUsedToMatch":true},{"id":"log_to_cloudflare","type":"string","display":true,"required":false,"displayName":"log_to_cloudflare","defaultMatch":false,"canBeUsedToMatch":true},{"id":"max_upload","type":"string","display":true,"required":false,"displayName":"max_upload","defaultMatch":false,"canBeUsedToMatch":true},{"id":"min_tls_version","type":"string","display":true,"required":false,"displayName":"min_tls_version","defaultMatch":false,"canBeUsedToMatch":true},{"id":"minify","type":"string","display":true,"required":false,"displayName":"minify","defaultMatch":false,"canBeUsedToMatch":true},{"id":"mirage","type":"string","display":true,"required":false,"displayName":"mirage","defaultMatch":false,"canBeUsedToMatch":true},{"id":"mobile_redirect","type":"string","display":true,"required":false,"displayName":"mobile_redirect","defaultMatch":false,"canBeUsedToMatch":true},{"id":"opportunistic_encryption","type":"string","display":true,"required":false,"displayName":"opportunistic_encryption","defaultMatch":false,"canBeUsedToMatch":true},{"id":"opportunistic_onion","type":"string","display":true,"required":false,"displayName":"opportunistic_onion","defaultMatch":false,"canBeUsedToMatch":true},{"id":"orange_to_orange","type":"string","display":true,"required":false,"displayName":"orange_to_orange","defaultMatch":false,"canBeUsedToMatch":true},{"id":"origin_error_page_pass_thru","type":"string","display":true,"required":false,"displayName":"origin_error_page_pass_thru","defaultMatch":false,"canBeUsedToMatch":true},{"id":"polish","type":"string","display":true,"required":false,"displayName":"polish","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prefetch_preload","type":"string","display":true,"required":false,"displayName":"prefetch_preload","defaultMatch":false,"canBeUsedToMatch":true},{"id":"privacy_pass","type":"string","display":true,"required":false,"displayName":"privacy_pass","defaultMatch":false,"canBeUsedToMatch":true},{"id":"proxy_read_timeout","type":"string","display":true,"required":false,"displayName":"proxy_read_timeout","defaultMatch":false,"canBeUsedToMatch":true},{"id":"pseudo_ipv4","type":"string","display":true,"required":false,"displayName":"pseudo_ipv4","defaultMatch":false,"canBeUsedToMatch":true},{"id":"response_buffering","type":"string","display":true,"required":false,"displayName":"response_buffering","defaultMatch":false,"canBeUsedToMatch":true},{"id":"rocket_loader","type":"string","display":true,"required":false,"displayName":"rocket_loader","defaultMatch":false,"canBeUsedToMatch":true},{"id":"security_header","type":"string","display":true,"required":false,"displayName":"security_header","defaultMatch":false,"canBeUsedToMatch":true},{"id":"security_level","type":"string","display":true,"required":false,"displayName":"security_level","defaultMatch":false,"canBeUsedToMatch":true},{"id":"server_side_exclude","type":"string","display":true,"required":false,"displayName":"server_side_exclude","defaultMatch":false,"canBeUsedToMatch":true},{"id":"sort_query_string_for_cache","type":"string","display":true,"required":false,"displayName":"sort_query_string_for_cache","defaultMatch":false,"canBeUsedToMatch":true},{"id":"ssl","type":"string","display":true,"required":false,"displayName":"ssl","defaultMatch":false,"canBeUsedToMatch":true},{"id":"tls_1_2_only","type":"string","display":true,"required":false,"displayName":"tls_1_2_only","defaultMatch":false,"canBeUsedToMatch":true},{"id":"tls_1_3","type":"string","display":true,"required":false,"displayName":"tls_1_3","defaultMatch":false,"canBeUsedToMatch":true},{"id":"tls_client_auth","type":"string","display":true,"required":false,"displayName":"tls_client_auth","defaultMatch":false,"canBeUsedToMatch":true},{"id":"true_client_ip_header","type":"string","display":true,"required":false,"displayName":"true_client_ip_header","defaultMatch":false,"canBeUsedToMatch":true},{"id":"visitor_ip","type":"string","display":true,"required":false,"displayName":"visitor_ip","defaultMatch":false,"canBeUsedToMatch":true},{"id":"waf","type":"string","display":true,"required":false,"displayName":"waf","defaultMatch":false,"canBeUsedToMatch":true},{"id":"webp","type":"string","display":true,"required":false,"displayName":"webp","defaultMatch":false,"canBeUsedToMatch":true},{"id":"websockets","type":"string","display":true,"required":false,"displayName":"websockets","defaultMatch":false,"canBeUsedToMatch":true},{"id":"ech","type":"string","display":true,"required":false,"displayName":"ech","defaultMatch":false,"canBeUsedToMatch":true},{"id":"long_lived_grpc","type":"string","display":true,"required":false,"displayName":"long_lived_grpc","defaultMatch":false,"canBeUsedToMatch":true},{"id":"pq_keyex","type":"string","display":true,"required":false,"displayName":"pq_keyex","defaultMatch":false,"canBeUsedToMatch":true},{"id":"replace_insecure_js","type":"string","display":true,"required":false,"displayName":"replace_insecure_js","defaultMatch":false,"canBeUsedToMatch":true},{"id":"json_records","type":"string","display":true,"required":false,"displayName":"json_records","defaultMatch":false,"canBeUsedToMatch":true},{"id":"pairedItem_item","type":"string","display":true,"required":false,"displayName":"pairedItem_item","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"autoMapInputData","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":974904725,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1jt6od8FMt-Yo7A_CPGuyfqWzL7HJk6SZmQQFO6kkWBo/edit#gid=974904725","cachedResultName":"data"},"documentId":{"__rl":true,"mode":"id","value":"=1jt6od8FMt-Yo7A_CPGuyfqWzL7HJk6SZmQQFO6kkWBo"}},"credentials":{"googleSheetsOAuth2Api":{"id":"1G0QLMadkHt22pU8","name":"Google Sheets account"}},"executeOnce":false,"typeVersion":4.5}],"pinData":{},"connections":{"Wait":{"main":[[{"node":"Increment Page","type":"main","index":0}]]},"Merge":{"main":[[{"node":"More Pages?","type":"main","index":0}]]},"Flatten":{"main":[[{"node":"Export","type":"main","index":0}]]},"Get DNS":{"main":[[{"node":"Filter DNS","type":"main","index":0}]]},"Get TLDs":{"main":[[{"node":"Each Host","type":"main","index":0}]]},"Set Page":{"main":[[{"node":"Get TLDs","type":"main","index":0}]]},"Each Host":{"main":[[{"node":"Get Settings","type":"main","index":0},{"node":"Get DNS","type":"main","index":0},{"node":"Filter TLD","type":"main","index":0}]]},"Filter DNS":{"main":[[{"node":"Merge","type":"main","index":2}]]},"Filter TLD":{"main":[[{"node":"Merge","type":"main","index":0}]]},"More Pages?":{"main":[[{"node":"Wait","type":"main","index":0},{"node":"Flatten","type":"main","index":0}],[{"node":"Flatten","type":"main","index":0}]]},"Get Settings":{"main":[[{"node":"Filter Settings","type":"main","index":0}]]},"Increment Page":{"main":[[{"node":"Set Page","type":"main","index":0}]]},"Filter Settings":{"main":[[{"node":"Merge","type":"main","index":1}]]},"When clicking ‘Test workflow’":{"main":[[{"node":"Set Page","type":"main","index":0}]]}}}


name: Find relevant X tweets based on your profile and suggest responses
author_name: @OnePromptMagic
author_username: one-prompt-magic
categories: []
created_at: 2025-06-10T10:37:48.703Z
updated_at: 2025-06-10T10:37:48.703Z
url: https://n8n.io/workflows/4851
scraped_at: 2025-06-19 22:49:40
description:
  What This Workflow Does

  Step 1: Analyzes your recent tweets for personality & style
  Step 2: Generates strategic keywords based on your profile
  Step 3: Searches for trending tweets in your niche
  Step 4: Creates personalized responses & original tweets
  Step 5: Displays results in beautiful HTML format

  How to Use
  Execute the workflow
  Fill out the form with:
     Your X username (from your URL)
     Your goals on X (multiple selection)
     Optional additional info
  Submit the form
  Wait for processing (2-3 minutes)
  Double-click the "Click to show Result" node

  example clip can be found here

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

workflow_json:
  {"id":"kMKlrWsoDftOxsqE","meta":{"templateCredsSetupCompleted":true},"name":"X Tweet Suggestions","tags":[],"nodes":[{"id":"5fc895f6-b188-4900-81c7-b0eeebd1d571","name":"Get User Tweets","type":"n8n-nodes-base.httpRequest","position":[-1220,240],"parameters":{"url":"https://api.twitterapi.io/twitter/user/last_tweets","options":{"timeout":30000},"sendQuery":true,"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth","queryParameters":{"parameters":[{"name":"userName","value":"={{ $json[\"What's your name on X (it's within your url)\"] }}"},{"name":"count","value":"20"}]}},"credentials":{"httpHeaderAuth":{"id":"ptKPKaEhgzwgwNXi","name":"Header Auth account"}},"typeVersion":4.2,"continueOnFail":true},{"id":"299a1ada-646c-453c-85e5-c340e6df2dfc","name":"Map Tweets","type":"n8n-nodes-base.code","position":[-1220,440],"parameters":{"jsCode":"\n return { tweets: $input.first().json.data.tweets };\n  \n\n"},"typeVersion":2},{"id":"72b79ff2-055b-4842-8a60-7b8cef9dedd0","name":"On form submission","type":"n8n-nodes-base.formTrigger","position":[-1220,0],"webhookId":"cf0416df-72fb-4660-9f6a-1b29d03a18ec","parameters":{"options":{},"formTitle":"Perfect Niche Tweets","formFields":{"values":[{"fieldLabel":"What's your name on X (it's within your url)","placeholder":"OnePromptMagic"},{"fieldType":"dropdown","fieldLabel":"What are your current goals on X","multiselect":true,"fieldOptions":{"values":[{"option":"Increase followers"},{"option":"Boost impressions or reach"},{"option":"Boost engagement"},{"option":"Write a viral tweet"},{"option":"Just be helpful and motivating"}]}},{"fieldLabel":"Additional Infos (Optional)","placeholder":"I'm recently deep into n8n flows, publishing one flow a week, incorporate that where it fits"}]},"formDescription":"Enter your details and goals, we will then analyse your profile, analyse trendings topics that might be a good fit for you and finally draft some perfect tweets for you"},"typeVersion":2.2},{"id":"ce05506b-fba3-40ff-a28f-24434175f6b7","name":"Split Out","type":"n8n-nodes-base.splitOut","position":[-320,240],"parameters":{"options":{},"fieldToSplitOut":"queries"},"typeVersion":1},{"id":"445f99d3-95ec-4c94-95b7-c64bb0783da1","name":"Aggregate","type":"n8n-nodes-base.aggregate","position":[120,0],"parameters":{"options":{},"fieldsToAggregate":{"fieldToAggregate":[{"fieldToAggregate":"tweets"}]}},"typeVersion":1},{"id":"0511ce11-d316-4598-9e49-9a4df3e8dc95","name":"Tweet Writer","type":"@n8n/n8n-nodes-langchain.agent","position":[60,320],"parameters":{"text":"=you are an expert on X conversions and brand building. the user has the following goals:  {{ $('On form submission').item.json[\"What are your current goals on X\"] }}\nhere is the user's detailed user profile: {{ $('User Profile Analyser').item.json.output.toJsonString() }}\nhere is the user's bio: {{ $('Map Tweets').item.json.tweets[0].author.profile_bio.toJsonString()[\"description\"] }}\nHere are trending tweets that might be interesting for the user to interact with: \n{{ $json.tweets.toJsonString() }}\ncraft 10 tweets for the user, either interact with one of the listed tweets or craft an original tweet, based on what you think will bring the user closer to their goal. You can only write up to 2 original tweet, all others have to be responses. When responding, try to engage with the author, not self promote. Never write hashtags within the tweets. Use exclamation marks sparingly. Keep text short and authentic. some sarcasm can help, as long as it's not cringeworthy.\n\n🚫 Words to Avoid (AI Red Flags)\nNever overuse these AI-typical words:\nCrucial, delve, dive, tapestry\nFurthermore, consequently, moreover\n\"In today's [adjective] world of...\"\n\"Not only... but also\"\n\"By [doing X]...\" (especially in conclusions)\n✅ AI Writing Instructions\n1. Vary Sentence Structure\nMix short sentences (5-10 words) with longer ones (15-25 words)\nAvoid starting consecutive sentences with the same word patterns\nUse contractions naturally (don't, won't, it's, we're)\nBreak up long paragraphs with single-sentence paragraphs for emphasis\n2. Simulate Personal Voice\nUse first-person occasionally: \"I've noticed...\", \"In my view...\"\nInclude hypothetical scenarios: \"Imagine if...\", \"Picture this...\"\nReference common experiences: \"We've all been there when...\"\n3. Break Formulaic Patterns\nAvoid repetitive paragraph structures (intro-body-conclusion format)\nDon't restate the same concept multiple times in different words\nVary transition words instead of always using \"however,\" \"therefore,\" \"additionally\"\n4. Natural Language Patterns\nUse incomplete sentences for emphasis. Like this.\nInclude rhetorical questions to engage readers\nAdd mild interruptions with em-dashes--like this--for natural flow\nUse casual connectors: \"Plus,\" \"And here's the thing,\" \"Look,\"\n5. Content Structure Variation\nStart some paragraphs with questions\nUse specific numbers instead of vague terms (say \"73%\" not \"most\")\nInclude conversational asides in parentheses (because who doesn't love those?)\nVary list formats: bullets, numbers, and embedded lists within paragraphs\n6. Tone Authenticity\nMatch the complexity level to the audience consistently\nUse industry jargon appropriately but sparingly\nInclude mild opinions and stance-taking language\nWrite with confident assertions rather than hedging every statement\nKey instruction: Simulate the natural inconsistencies and stylistic quirks that make human writing distinctive.\n\ntweets to ignore: anything crypto related, politics\nif in the relevant tweets array there are several tweets of the same user, only respond to up to 1 one of those.\n\nHere is additional info by the user for this request:\n{{ $('On form submission').item.json[\"Additional Infos (Optional)\"] }}","options":{},"promptType":"define","hasOutputParser":true},"typeVersion":2},{"id":"8d2da454-3561-4ddc-8df7-b5d535a4411f","name":"User Profile Analyser","type":"@n8n/n8n-nodes-langchain.agent","position":[-840,0],"parameters":{"text":"=You will provide a detailed user profile of an X user based on their recent tweets. Your output will serve to create new tweets for this user, that have the same feel, punctuation patterns, language hickups, emoji usage, use of abbreviation, humor and flow of story as the user. so go as detailed as possible on what you can find out, so that the next agent can work with your ouput to craft a tweet.\nhere are the user's last tweets: \n{{ $json.tweets.toJsonString() }}\n","options":{},"promptType":"define","hasOutputParser":true},"typeVersion":2},{"id":"59bfbd43-e08b-4369-9db5-b0a24fa7312d","name":"Keyword Analyser","type":"@n8n/n8n-nodes-langchain.agent","position":[-840,320],"parameters":{"text":"=You are an expert Twitter trend analyst. Analyze the user's profile and generate 3 groups of related keywords that will find relevant, high-engagement tweets for their goals.\n\nUser Profile Analysis:\n{{ $json.output.toJsonString() }}\n\nUser Additional Input: \n{{ $('On form submission').item.json[\"Additional Infos (Optional)\"] || \"none\" }}\n\nYour Mission:\nGenerate 3 groups of keywords (3-5 keywords per group) that align with the user's expertise and goals. Each group should target different aspects of their interests.\n\nFocus on:\n- Specific terminology in their field\n- Related concepts and synonyms  \n- Industry jargon and buzzwords\n- Trending topics in their niche\n- Tools and technologies they use\n\nGuidelines:\n- Use exact phrases that people actually tweet about\n- Include both formal and casual variations\n- Consider abbreviations and acronyms\n- Think about what thought leaders in their field discuss\n- Focus on actionable, engaging content\n\nExample:\nIf user is into AI automation:\nGroup 1: [\"AI agents\", \"autonomous AI\", \"AI automation\", \"agent orchestration\"] \nGroup 2: [\"no code\", \"workflow automation\", \"AI tools\", \"automation tools\"]\nGroup 3: [\"cursor\", \"AI coding\", \"AI development\", \"LLM integration\"]\n\nOutput exactly 3 keyword groups that will find the most relevant tweets for engagement opportunities.","options":{},"promptType":"define","hasOutputParser":true},"typeVersion":2},{"id":"98f3a6f6-397b-48b8-8770-0aa89720ed4b","name":"Get relevant tweets","type":"n8n-nodes-base.httpRequest","position":[-320,460],"parameters":{"url":"https://api.twitterapi.io/twitter/tweet/advanced_search","options":{},"sendQuery":true,"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth","queryParameters":{"parameters":[{"name":"query","value":"={{ $json[\"queries\"] }}"},{"name":"queryType","value":"Top"}]}},"credentials":{"httpHeaderAuth":{"id":"ptKPKaEhgzwgwNXi","name":"Header Auth account"}},"typeVersion":4.2},{"id":"8c513d94-3aec-4094-8989-572cb019a258","name":"Click to show Result","type":"n8n-nodes-base.html","position":[600,440],"parameters":{"html":"{{ $json.html }}"},"typeVersion":1.2},{"id":"0d75fcdf-83d4-4eed-b5b7-84521948022e","name":"Replace em dash","type":"n8n-nodes-base.code","position":[600,0],"parameters":{"jsCode":"const items = [];\n\nfor (const item of $input.all()) {\n  const data = item.json;\n  \n  if (!data.output || !data.output.tweets || !Array.isArray(data.output.tweets)) {\n    items.push({\n      json: data\n    });\n    continue;\n  }\n  \n  const processedTweets = data.output.tweets.map(tweet => {\n    return {\n      ...tweet,\n      text: tweet.text ? tweet.text.replace(/--/g, ' - ') : tweet.text\n    };\n  });\n  \n  items.push({\n    json: {\n      ...data,\n      output: {\n        ...data.output,\n        tweets: processedTweets\n      }\n    }\n  });\n}\n\nreturn items;"},"typeVersion":2},{"id":"4478ff3c-b653-4e4d-bd03-2b10b13b8265","name":"combine keywords","type":"n8n-nodes-base.code","position":[-320,0],"parameters":{"jsCode":"const items = [];\n\nfor (const item of $input.all()) {\n  const data = item.json;\n  const userGoals = $('On form submission').item.json[\"What are your current goals on X\"];\n  \n  const keywordGroups = data.output.keyword_groups || [];\n  \n  const wantsViral = userGoals && userGoals.includes(\"Write a viral tweet\");\n  const wantsFollowers = userGoals && userGoals.includes(\"Increase followers\");\n  \n  const queries = [];\n  \n  keywordGroups.forEach((group, index) => {\n    const keywordQuery = group.map(keyword => `\"${keyword}\"`).join(\" OR \");\n    \n    let searchQuery = `(${keywordQuery})`;\n    \n    searchQuery += \" within_time:2d\";\n    \n    if (wantsViral) {\n      searchQuery += \" min_faves:200 min_retweets:20\";\n    } else if (wantsFollowers) {\n      searchQuery += \" min_faves:100 min_retweets:10\";\n    } else {\n      searchQuery += \" min_faves:50\";\n    }\n    \n    searchQuery += \" lang:en -$ -filter:retweets\";\n    \n    if (index === 0) {\n      searchQuery += \" filter:verified\";\n    } else if (index === 1) {\n      searchQuery += \" filter:blue_verified\";\n    }\n    \n    queries.push(searchQuery);\n  });\n  \n  items.push({\n    json: {\n      queries: queries,\n      user_goals: userGoals,\n      wants_viral: wantsViral,\n      original_keyword_groups: keywordGroups\n    }\n  });\n}\n\nreturn items;"},"typeVersion":2},{"id":"61f53128-9ef7-4638-81ff-a752a62510a4","name":"o3-mini","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-840,180],"parameters":{"model":{"__rl":true,"mode":"list","value":"o3-mini","cachedResultName":"o3-mini"},"options":{}},"credentials":{"openAiApi":{"id":"q4srYaXuPZeNbtbt","name":"OpenAi account"}},"typeVersion":1.2},{"id":"de12f5b8-38b5-41b8-bfb8-756f40e98668","name":"profile schema","type":"@n8n/n8n-nodes-langchain.outputParserStructured","position":[-660,180],"parameters":{"schemaType":"manual","inputSchema":"{\n  \"type\": \"object\",\n  \"properties\": {\n    \"examplePrompt\": {\n      \"type\": \"string\",\n      \"description\": \"This should be one of their best tweets (just as is, nothing changed)\"\n    },\n    \"punctuation\": {\n      \"type\": \"string\",\n      \"description\": \"User's punctuation style and patterns\"\n    },\n    \"personalityType\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"Extraverted sensation\",\n        \"Introverted sensation\", \n        \"Extraverted intuition\",\n        \"Introverted intuition\",\n        \"Extraverted thinking\",\n        \"Introverted thinking\",\n        \"Extraverted feeling\",\n        \"Introverted feeling\"\n      ],\n      \"description\": \"Dominant cognitive function based on user's communication style\"\n    },\n    \"humorType\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"Physical comedy or slapstick comedy\",\n        \"Aggressive humor\",\n        \"Self-enhancing humor\", \n        \"Self-defeating humor\",\n        \"Affiliative humor\",\n        \"Self-deprecating humor\",\n        \"Observational humor\",\n        \"Dry humor\"\n      ],\n      \"description\": \"Primary humor style used by the user\"\n    },\n    \"fieldOfExpertise\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"maxItems\": 5,\n      \"description\": \"User's areas of expertise (up to 5)\"\n    },\n    \"recognizedPatterns\": {\n      \"type\": \"string\",\n      \"description\": \"This could be something like 'user always starts with this', or 'user often uses the pray emoji', etc.\"\n    }\n  },\n  \"required\": [\"examplePrompt\"],\n  \"additionalProperties\": false\n}"},"typeVersion":1.2},{"id":"3ed5bc68-5456-4fd5-a1d6-d3c2fa05fc94","name":"4.1-mini","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-840,500],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4.1-mini","cachedResultName":"gpt-4.1-mini"},"options":{}},"credentials":{"openAiApi":{"id":"q4srYaXuPZeNbtbt","name":"OpenAi account"}},"typeVersion":1.2},{"id":"592ede7f-1a72-480a-8090-740906cb9d21","name":"keywords schema","type":"@n8n/n8n-nodes-langchain.outputParserStructured","position":[-660,500],"parameters":{"schemaType":"manual","inputSchema":"{\n  \"type\": \"object\",\n  \"properties\": {\n    \"keyword_groups\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"array\", \n        \"items\": {\n          \"type\": \"string\"\n        },\n        \"minItems\": 3,\n        \"maxItems\": 5,\n        \"description\": \"A group of 3-5 related keywords that will be combined with OR\"\n      },\n      \"minItems\": 3,\n      \"maxItems\": 3,\n      \"description\": \"3 groups of related keywords, each targeting different aspects of user's interests\"\n    }\n  },\n  \"required\": [\"keyword_groups\"],\n  \"additionalProperties\": false\n}"},"typeVersion":1.2},{"id":"debdaf4b-4c3e-4797-b1e4-1b0f118175e7","name":"o3-mini1","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[60,500],"parameters":{"model":{"__rl":true,"mode":"list","value":"o3-mini","cachedResultName":"o3-mini"},"options":{}},"credentials":{"openAiApi":{"id":"q4srYaXuPZeNbtbt","name":"OpenAi account"}},"typeVersion":1.2},{"id":"8745739b-1a0f-4390-accb-8127c5602f0e","name":"tweet schema","type":"@n8n/n8n-nodes-langchain.outputParserStructured","position":[260,500],"parameters":{"schemaType":"manual","inputSchema":"{\n  \"type\": \"object\",\n  \"properties\": {\n    \"tweets\": {\n      \"type\": \"array\",\n      \"minItems\": 5,\n      \"maxItems\": 10,\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"priority\": {\n            \"type\": \"integer\",\n            \"minimum\": 1,\n            \"maximum\": 5,\n            \"description\": \"Priority level from 1-5 (1 is highest priority, 5 is lowest priority)\"\n          },\n          \"text\": {\n            \"type\": \"string\",\n            \"description\": \"The tweet text content\"\n          },\n          \"isAnswer\": {\n            \"type\": \"boolean\",\n            \"description\": \"If true, the tweet is a response to one of the listed tweets; if false, it's an original tweet by the user\"\n          },\n          \"tweetUrl\": {\n            \"type\": \"string\",\n            \"description\": \"The URL to the tweet to respond to (required only if isAnswer is true)\"\n          },\n          \"reasoning\": {\n            \"type\": \"string\",\n            \"description\": \"Concise reason why this tweet will bring the user closer to their goal\"\n          }\n        },\n        \"required\": [\"priority\", \"text\", \"isAnswer\", \"reasoning\"],\n        \"additionalProperties\": false,\n        \"if\": {\n          \"properties\": {\n            \"isAnswer\": {\n              \"const\": true\n            }\n          }\n        },\n        \"then\": {\n          \"required\": [\"priority\", \"text\", \"isAnswer\", \"tweetUrl\", \"reasoning\"]\n        }\n      },\n      \"description\": \"Array of 1-5 tweet suggestions with priority and context\"\n    }\n  },\n  \"required\": [\"tweets\"],\n  \"additionalProperties\": false\n}"},"typeVersion":1.2},{"id":"fb0151fe-e279-4a7e-b60c-0c318c16bc91","name":"Prepare Result","type":"n8n-nodes-base.code","position":[600,220],"parameters":{"jsCode":"const items = [];\n\nfor (const item of $input.all()) {\n  const data = item.json;\n  \n  const aggregateNodeData = $('Aggregate').all();\n  \n  const originalTweetsMap = {};\n  \n  let debugUrls = [];\n  \n  if (aggregateNodeData && aggregateNodeData.length > 0) {\n    aggregateNodeData.forEach((nodeItem, nodeIndex) => {\n      if (nodeItem.json && nodeItem.json.tweets) {\n        \n        if (Array.isArray(nodeItem.json.tweets)) {\n          nodeItem.json.tweets.forEach((tweetGroup, groupIndex) => {\n            if (Array.isArray(tweetGroup)) {\n              tweetGroup.forEach((tweet, tweetIndex) => {\n                if (tweet && typeof tweet === 'object') {\n                  let username = 'unknown';\n                  let authorName = 'Unknown User';\n                  \n                  if (tweet.author) {\n                    username = tweet.author.username || tweet.author.screen_name || tweet.author.handle || 'unknown';\n                    authorName = tweet.author.name || tweet.author.display_name || 'Unknown User';\n                  }\n                  \n                  if (!username || username === 'unknown') {\n                    username = tweet.username || tweet.screen_name || tweet.handle || 'unknown';\n                  }\n                  if (!authorName || authorName === 'Unknown User') {\n                    authorName = tweet.author_name || tweet.name || 'Unknown User';\n                  }\n                  \n                  const tweetData = {\n                    text: tweet.text,\n                    author: username,\n                    authorName: authorName\n                  };\n                  \n                  if (tweet.url && tweet.text) {\n                    originalTweetsMap[tweet.url] = tweetData;\n                    debugUrls.push(tweet.url);\n                  }\n                  if (tweet.twitterUrl && tweet.text) {\n                    originalTweetsMap[tweet.twitterUrl] = tweetData;\n                    debugUrls.push(tweet.twitterUrl);\n                  }\n                  \n                  if (tweet.url) {\n                    const normalizedUrl = tweet.url.replace('https://x.com', 'https://twitter.com');\n                    originalTweetsMap[normalizedUrl] = tweetData;\n                  }\n                  if (tweet.twitterUrl) {\n                    const normalizedUrl = tweet.twitterUrl.replace('https://twitter.com', 'https://x.com');\n                    originalTweetsMap[normalizedUrl] = tweetData;\n                  }\n                }\n              });\n            } else if (tweetGroup && typeof tweetGroup === 'object') {\n              let username = 'unknown';\n              let authorName = 'Unknown User';\n              \n              if (tweetGroup.author) {\n                username = tweetGroup.author.username || tweetGroup.author.screen_name || tweetGroup.author.handle || 'unknown';\n                authorName = tweetGroup.author.name || tweetGroup.author.display_name || 'Unknown User';\n              }\n              \n              if (!username || username === 'unknown') {\n                username = tweetGroup.username || tweetGroup.screen_name || tweetGroup.handle || 'unknown';\n              }\n              if (!authorName || authorName === 'Unknown User') {\n                authorName = tweetGroup.author_name || tweetGroup.name || 'Unknown User';\n              }\n              \n              const tweetData = {\n                text: tweetGroup.text,\n                author: username,\n                authorName: authorName\n              };\n              \n              if (tweetGroup.url && tweetGroup.text) {\n                originalTweetsMap[tweetGroup.url] = tweetData;\n                debugUrls.push(tweetGroup.url);\n              }\n              if (tweetGroup.twitterUrl && tweetGroup.text) {\n                originalTweetsMap[tweetGroup.twitterUrl] = tweetData;\n                debugUrls.push(tweetGroup.twitterUrl);\n              }\n            }\n          });\n        }\n      }\n    });\n  }\n  \n  if (!data.output || !data.output.tweets || !Array.isArray(data.output.tweets)) {\n    items.push({\n      json: {\n        html: '<div>No tweets data found</div>'\n      }\n    });\n    continue;\n  }\n  \n  const tweets = data.output.tweets;\n  const responseOpportunities = tweets.filter(t => t.isAnswer);\n  const originalTweets = tweets.filter(t => !t.isAnswer);\n  \n  // Debug: track which URLs we're looking for vs what we found\n  const lookingFor = responseOpportunities.map(t => t.tweetUrl);\n  const notFound = [];\n  const skippedUnknown = [];\n  \n  let tweetsHtml = '';\n  \n  responseOpportunities.forEach((tweet, index) => {\n    let originalTweetData = originalTweetsMap[tweet.tweetUrl];\n    \n    if (!originalTweetData) {\n      const normalizedUrl1 = tweet.tweetUrl.replace('https://x.com', 'https://twitter.com');\n      const normalizedUrl2 = tweet.tweetUrl.replace('https://twitter.com', 'https://x.com');\n      originalTweetData = originalTweetsMap[normalizedUrl1] || originalTweetsMap[normalizedUrl2];\n    }\n    \n    if (!originalTweetData || \n        originalTweetData.authorName === 'Unknown User' || \n        originalTweetData.text === 'Original tweet text not available') {\n      skippedUnknown.push(tweet.tweetUrl);\n      notFound.push(tweet.tweetUrl);\n      return;\n    }\n    \n    const originalTweetText = originalTweetData.text;\n    const authorInfo = originalTweetData.authorName;\n    \n    const isAnswerBadge = '<span style=\"background: #8b5cf6; color: white; padding: 6px 12px; border-radius: 20px; font-size: 12px; font-weight: 600; margin-bottom: 16px; display: inline-block;\">💬 Response Opportunity</span>';\n    \n    const tweetId = `tweet-response-${index}`;\n    const reasoningId = `reasoning-response-${index}`;\n    \n    tweetsHtml += `\n      <div style=\"border-bottom: 2px solid #e5e7eb; padding: 24px;\">\n        ${isAnswerBadge}\n        \n        <!-- Original Tweet -->\n        <div style=\"margin-bottom: 20px;\">\n          <div style=\"display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;\">\n            <div style=\"color: #6b7280; font-size: 14px;\">\n              <strong>${authorInfo}</strong>\n            </div>\n            <button onclick=\"toggleReasoning('${reasoningId}')\" style=\"background: #6b7280; color: white; border: none; padding: 4px 8px; border-radius: 4px; cursor: pointer; font-size: 10px; transition: background 0.2s;\" onmouseover=\"this.style.background='#4b5563'\" onmouseout=\"this.style.background='#6b7280'\">\n              ℹ️\n            </button>\n          </div>\n          \n          <div onclick=\"window.open('${tweet.tweetUrl}', '_blank')\" style=\"background: #f9fafb; padding: 16px; border-radius: 8px; border-left: 4px solid #1da1f2; margin-bottom: 12px; cursor: pointer; transition: background 0.2s;\" onmouseover=\"this.style.background='#f3f4f6'\" onmouseout=\"this.style.background='#f9fafb'\">\n            ${originalTweetText}\n          </div>\n          \n          <div style=\"background: #fafafa; padding: 8px 12px; border-radius: 6px; font-family: monospace; font-size: 11px; word-break: break-all; margin-bottom: 8px;\">\n            <strong>URL:</strong> <a href=\"${tweet.tweetUrl}\" target=\"_blank\" style=\"color: #1da1f2; text-decoration: none;\">${tweet.tweetUrl}</a>\n          </div>\n          \n          <!-- Hidden Reasoning -->\n          <div id=\"${reasoningId}\" style=\"display: none; background: #fff3cd; padding: 12px; border-radius: 6px; margin-top: 12px; border-left: 4px solid #ffc107;\">\n            <strong>Strategic Analysis:</strong> ${tweet.reasoning}\n          </div>\n        </div>\n\n        <!-- Suggested Response -->\n        <div>\n          <h3 style=\"color: #374151; margin: 0 0 12px 0; font-size: 16px;\">✨ Your Response</h3>\n          <div id=\"${tweetId}\" onclick=\"copyResponseText('${tweetId}')\" style=\"background: #f0fdf4; padding: 16px; border-radius: 8px; border-left: 4px solid #10b981; margin-bottom: 12px; cursor: pointer; transition: all 0.2s;\" onmouseover=\"this.style.background='#dcfce7'; this.style.transform='translateY(-1px)'; this.style.boxShadow='0 4px 12px rgba(16, 185, 129, 0.15)'\" onmouseout=\"this.style.background='#f0fdf4'; this.style.transform='translateY(0)'; this.style.boxShadow='none'\">\n            ${tweet.text}\n          </div>\n        </div>\n        \n      </div>\n    `;\n  });\n  \n  originalTweets.forEach((tweet, index) => {\n    const originalBadge = '<span style=\"background: #f59e0b; color: white; padding: 6px 12px; border-radius: 20px; font-size: 12px; font-weight: 600; margin-bottom: 16px; display: inline-block;\">✨ Original Tweet</span>';\n    \n    const tweetId = `tweet-original-${index}`;\n    const reasoningId = `reasoning-original-${index}`;\n    \n    tweetsHtml += `\n      <div style=\"border-bottom: 2px solid #e5e7eb; padding: 24px;\">\n        ${originalBadge}\n        \n        <!-- Original Tweet Content -->\n        <div style=\"margin-bottom: 20px;\">\n          <div style=\"display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px;\">\n            <h3 style=\"color: #374151; margin: 0; font-size: 16px;\">🎯 Your Original Tweet</h3>\n            <button onclick=\"toggleReasoning('${reasoningId}')\" style=\"background: #6b7280; color: white; border: none; padding: 4px 8px; border-radius: 4px; cursor: pointer; font-size: 10px; transition: background 0.2s;\" onmouseover=\"this.style.background='#4b5563'\" onmouseout=\"this.style.background='#6b7280'\">\n              ℹ️\n            </button>\n          </div>\n          \n          <div id=\"${tweetId}\" onclick=\"copyResponseText('${tweetId}')\" style=\"background: #fef3c7; padding: 16px; border-radius: 8px; border-left: 4px solid #f59e0b; margin-bottom: 12px; cursor: pointer; transition: all 0.2s;\" onmouseover=\"this.style.background='#fde68a'; this.style.transform='translateY(-1px)'; this.style.boxShadow='0 4px 12px rgba(245, 158, 11, 0.15)'\" onmouseout=\"this.style.background='#fef3c7'; this.style.transform='translateY(0)'; this.style.boxShadow='none'\">\n            ${tweet.text}\n          </div>\n          \n          <!-- Hidden Reasoning for Original Tweet -->\n          <div id=\"${reasoningId}\" style=\"display: none; background: #ede9fe; padding: 12px; border-radius: 6px; margin-top: 12px; border-left: 4px solid #8b5cf6;\">\n            <strong>Strategic Reasoning:</strong> ${tweet.reasoning}\n          </div>\n        </div>\n        \n      </div>\n    `;\n  });\n\n  let debugSection = '';\n  if (notFound.length > 0) {\n    debugSection = `\n      <div style=\"padding: 20px; background: #fef2f2; border-top: 1px solid #fecaca; margin-top: 20px;\">\n        <details style=\"font-size: 12px; color: #dc2626;\">\n          <summary style=\"cursor: pointer; font-weight: 600;\">🔍 Debug: ${notFound.length} tweets not shown</summary>\n          <div style=\"margin-top: 8px;\">\n            <p><strong>Total response opportunities:</strong> ${responseOpportunities.length}</p>\n            <p><strong>Shown:</strong> ${responseOpportunities.length - notFound.length}</p>\n            <p><strong>Hidden (unknown users/missing data):</strong> ${notFound.length}</p>\n            <p><strong>Original tweets shown:</strong> ${originalTweets.length}</p>\n            <br>\n            <p><strong>URLs we're looking for:</strong></p>\n            <div style=\"font-family: monospace; font-size: 10px; background: white; padding: 8px; border-radius: 4px; margin: 4px 0;\">\n              ${lookingFor.map(url => `• ${url}`).join('<br>')}\n            </div>\n            <p><strong>URLs we found in data:</strong></p>\n            <div style=\"font-family: monospace; font-size: 10px; background: white; padding: 8px; border-radius: 4px; margin: 4px 0;\">\n              ${debugUrls.length > 0 ? debugUrls.map(url => `• ${url}`).join('<br>') : 'No URLs found in aggregate data'}\n            </div>\n            <p><strong>Skipped URLs (unknown/missing):</strong></p>\n            <div style=\"font-family: monospace; font-size: 10px; background: white; padding: 8px; border-radius: 4px; margin: 4px 0;\">\n              ${skippedUnknown.map(url => `• ${url}`).join('<br>')}\n            </div>\n          </div>\n        </details>\n      </div>\n    `;\n  }\n\n  const totalShown = (responseOpportunities.length - notFound.length) + originalTweets.length;\n  \n  const fullHtml = `\n    <div style=\"max-width: 800px; margin: 20px auto; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f8fafc; padding: 20px;\">\n      <div style=\"background: white; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); overflow: hidden;\">\n        \n        <div style=\"background: #000000; color: white; padding: 20px; text-align: center;\">\n          <h1 style=\"margin: 0; font-size: 24px;\">🚀 X Engagement Opportunities</h1>\n          <p style=\"margin: 10px 0 0 0; opacity: 0.9;\">Strategic responses and original content (${totalShown} suggestions)</p>\n        </div>\n\n        ${tweetsHtml}\n        ${debugSection}\n\n      </div>\n    </div>\n\n    <script>\n    function copyResponseText(elementId) {\n      const element = document.getElementById(elementId);\n      const text = element.textContent || element.innerText;\n      \n      if (navigator.clipboard && window.isSecureContext) {\n        navigator.clipboard.writeText(text.trim()).then(function() {\n          showNotification('✅ Tweet copied to clipboard!');\n          flashCopySuccess(elementId);\n        }).catch(function(err) {\n          fallbackCopy(text.trim());\n        });\n      } else {\n        fallbackCopy(text.trim());\n      }\n    }\n    \n    function fallbackCopy(text) {\n      const textArea = document.createElement('textarea');\n      textArea.value = text;\n      textArea.style.position = 'fixed';\n      textArea.style.left = '-999999px';\n      textArea.style.top = '-999999px';\n      document.body.appendChild(textArea);\n      textArea.focus();\n      textArea.select();\n      \n      try {\n        document.execCommand('copy');\n        showNotification('✅ Tweet copied to clipboard!');\n      } catch (err) {\n        showNotification('❌ Copy failed - please select and copy manually');\n      }\n      \n      document.body.removeChild(textArea);\n    }\n    \n    function flashCopySuccess(elementId) {\n      const element = document.getElementById(elementId);\n      const originalBg = element.style.backgroundColor;\n      element.style.backgroundColor = '#10b981';\n      element.style.color = 'white';\n      \n      setTimeout(() => {\n        element.style.backgroundColor = originalBg;\n        element.style.color = '';\n      }, 200);\n    }\n\n    function toggleReasoning(elementId) {\n      const element = document.getElementById(elementId);\n      if (element.style.display === 'none') {\n        element.style.display = 'block';\n      } else {\n        element.style.display = 'none';\n      }\n    }\n\n    function showNotification(message) {\n      const notification = document.createElement('div');\n      notification.textContent = message;\n      notification.style.cssText = 'position:fixed;top:20px;right:20px;background:#10b981;color:white;padding:12px 20px;border-radius:6px;z-index:1000;font-size:14px;box-shadow:0 4px 12px rgba(0,0,0,0.15); animation: slideIn 0.3s ease;';\n      document.body.appendChild(notification);\n      \n      setTimeout(() => {\n        if (document.body.contains(notification)) {\n          notification.style.animation = 'slideOut 0.3s ease';\n          setTimeout(() => {\n            if (document.body.contains(notification)) {\n              document.body.removeChild(notification);\n            }\n          }, 300);\n        }\n      }, 2000);\n    }\n    \n    // Add CSS for animations\n    const style = document.createElement('style');\n    style.textContent = \\`\n      @keyframes slideIn {\n        from { transform: translateX(100%); opacity: 0; }\n        to { transform: translateX(0); opacity: 1; }\n      }\n      @keyframes slideOut {\n        from { transform: translateX(0); opacity: 1; }\n        to { transform: translateX(100%); opacity: 0; }\n      }\n    \\`;\n    document.head.appendChild(style);\n    </script>\n  `;\n\n  items.push({\n    json: {\n      html: fullHtml,\n      tweet_count: totalShown,\n      response_opportunities: responseOpportunities.length - notFound.length,\n      original_tweets: originalTweets.length,\n      original_data: data,\n      debug_missing_tweets: notFound,\n      debug_skipped_unknown: skippedUnknown\n    }\n  });\n}\n\nreturn items;"},"typeVersion":2},{"id":"9306ec98-229c-44df-9be4-eb642eb49a35","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-1840,0],"parameters":{"color":7,"width":500,"height":660,"content":"## 📋 Setup Instructions\n\n### 1️⃣ Configure API Keys\n- Add your OpenAI credentials to the nodes\n\n- Get your twitterapi key from https://twitterapi.io?ref=1PROMPT (:pray:)\n- Add to \"Header Auth account\" credential\n- Used for fetching user tweets and trending content\n\n### 2️⃣ How to Use\n1. **Execute** the workflow\n2. **Fill out the form** with:\n   - Your X username (from your URL)\n   - Your goals on X (multiple selection)\n   - Optional additional info\n3. **Submit** the form\n4. **Wait** for processing (2-3 minutes)\n5. **Double-click** the \"Click to show Result\" node\n\n### 3️⃣ What This Workflow Does\n\n**Step 1:** Analyzes your recent tweets for personality & style\n**Step 2:** Generates strategic keywords based on your profile\n**Step 3:** Searches for trending tweets in your niche\n**Step 4:** Creates personalized responses & original tweets\n**Step 5:** Displays results in beautiful HTML format\n\nFollow https://x.com/OnePromptMagic for more free n8n templates\n"},"typeVersion":1},{"id":"39c40eba-dbf9-449e-b80c-147625ff4acc","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-580,-240],"parameters":{"color":7,"width":600,"height":80,"content":"# 🚀 X Tweet Suggestions Workflow"},"typeVersion":1}],"active":false,"scopes":["workflow:create","workflow:delete","workflow:execute","workflow:list","workflow:move","workflow:read","workflow:share","workflow:update"],"pinData":{},"settings":{"executionOrder":"v1"},"createdAt":"2025-06-07T04:31:44.088Z","updatedAt":"2025-06-10T05:43:37.000Z","versionId":"27278b7e-2af0-47d1-b904-8d25bbd300e2","isArchived":false,"staticData":null,"connections":{"o3-mini":{"ai_languageModel":[[{"node":"User Profile Analyser","type":"ai_languageModel","index":0}]]},"4.1-mini":{"ai_languageModel":[[{"node":"Keyword Analyser","type":"ai_languageModel","index":0}]]},"o3-mini1":{"ai_languageModel":[[{"node":"Tweet Writer","type":"ai_languageModel","index":0}]]},"Aggregate":{"main":[[{"node":"Tweet Writer","type":"main","index":0}]]},"Split Out":{"main":[[{"node":"Get relevant tweets","type":"main","index":0}]]},"Map Tweets":{"main":[[{"node":"User Profile Analyser","type":"main","index":0}]]},"Tweet Writer":{"main":[[{"node":"Replace em dash","type":"main","index":0}]]},"tweet schema":{"ai_outputParser":[[{"node":"Tweet Writer","type":"ai_outputParser","index":0}]]},"Prepare Result":{"main":[[{"node":"Click to show Result","type":"main","index":0}]]},"profile schema":{"ai_outputParser":[[{"node":"User Profile Analyser","type":"ai_outputParser","index":0}]]},"Get User Tweets":{"main":[[{"node":"Map Tweets","type":"main","index":0}]]},"Replace em dash":{"main":[[{"node":"Prepare Result","type":"main","index":0}]]},"keywords schema":{"ai_outputParser":[[{"node":"Keyword Analyser","type":"ai_outputParser","index":0}]]},"Keyword Analyser":{"main":[[{"node":"combine keywords","type":"main","index":0}]]},"combine keywords":{"main":[[{"node":"Split Out","type":"main","index":0}]]},"On form submission":{"main":[[{"node":"Get User Tweets","type":"main","index":0}]]},"Get relevant tweets":{"main":[[{"node":"Aggregate","type":"main","index":0}]]},"User Profile Analyser":{"main":[[{"node":"Keyword Analyser","type":"main","index":0}]]}},"triggerCount":0}


name: Automate GPT-4o Fine-Tuning with Google Sheets or Airtable Data
author_name: Matty Reed
author_username: mattyreed1
categories: []
created_at: 2025-06-10T12:18:16.840Z
updated_at: 2025-06-10T12:18:16.840Z
url: https://n8n.io/workflows/4853
scraped_at: 2025-06-19 22:49:36
description:
  Who is this for?  
  Anyone curating before/after text examples in a spreadsheet and wanting a push-button path to a fine-tuned GPT model—without touching curl. Works with Google Sheets or Airtable.

  What problem does it solve?  
  Manually downloading CSVs, converting to JSONL, uploading, and polling OpenAI is a slog.  
  This flow automates the whole loop: grab examples flagged Ready, build the JSONL file, start the fine-tune, then log the resulting model ID back to a registry sheet/table for reuse.

  How it works  

  | # | Node | Purpose |
  |---|------|---------|
  | 1 | Schedule Trigger | Runs weekly by default (change as needed). |
  | 2a | Get Examples from Sheet | Pulls rows where Ready = TRUE from your Google Sheet. Uses the JSONL-Template Sheet as the expected column layout. |
  | 2b | Get Examples from Airtable (disabled) | Alternate source for Airtable users. |
  | 3 | Create JSONL File (Code) | Converts each example to chat-format JSONL and splits into train.jsonl / val.jsonl (80/20). |
  | 4 | Upload JSONL | Uploads the training file to OpenAI (purpose: fine-tune). |
  | 5 | Begin Fine-Tune | Starts a fine-tune job on gpt-4o (editable). |
  | 6 | Wait → Check Job → IF | Polls every minute until status = succeeded. |
  | 7a | Write Model to Sheet | Appends the new model ID + meta to your Model Registry sheet. |
  | 7b | Write Model to Airtable (disabled) | Equivalent logging step for Airtable. |

  Setup steps  

  Import & connect credentials  
     Import the JSON flow into n8n.  
     Add your OpenAI API key.  
     Google Sheets: create an OAuth2 credential and link it to both Sheets nodes.  
     Airtable (optional): create a Personal Access Token and attach it to the Airtable nodes.

  Copy the template sheet  
     Duplicate the JSONL-Template Sheet linked above into your own Drive.  
     Required columns (exact names):  
       | systemPrompt | userPrompt | assistantResponse | Ready |  
     Tick Ready = TRUE for rows you want to include.

  Create the registry sheet/table  
     Google Sheet (or Airtable table) named Model Registry with columns:  
       Model ID, Training Examples, Epochs, Batch Size, Learning Rate, Finished At.

  Tweak model & schedule  
     Change the base model in Begin Fine-Tune if desired.  
     Adjust the Schedule Trigger for daily / on-demand runs.

  Test it  
     Mark a few examples Ready = TRUE.  
     Run the flow manually.  
     Check OpenAI for the new fine-tune job and confirm the model ID is logged in your registry.

  Resources  

  n8n Docs – &lt;https://docs.n8n.io/&gt;  
  OpenAI Fine-Tuning – &lt;https://platform.openai.com/docs/guides/fine-tuning&gt;  
  Google Sheets API – &lt;https://developers.google.com/sheets/api&gt;  
  Airtable API – &lt;https://airtable.com/api&gt;

  Extending the flow  

  Webhook trigger** – swap the schedule for a webhook to train on demand.  
  Multi-source merge* – enable both Sheets *and Airtable nodes to combine datasets.  
  Auto-deploy** – save the new model name to an env-var or Secrets Manager for downstream generation workflows.

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

workflow_json:
  {"id":"n5I2z5PXIENtW9ri","meta":{"instanceId":"78cd535d8c280c9f391d1c1efae71bb3b005620d19729d7bf9cd5c4e1509eeb2","templateCredsSetupCompleted":true},"name":"Fine Tune GPT","tags":[],"nodes":[{"id":"fc478cd0-8d84-4e8a-b0d8-7b2a4bb6b65c","name":"Wait","type":"n8n-nodes-base.wait","position":[1560,0],"webhookId":"441a25bb-a01c-4a27-a18b-3e242ea1c1b2","parameters":{},"typeVersion":1.1},{"id":"4a6895a6-5a5c-48f2-98ea-2c6ed1d428e3","name":"Schedule Trigger","type":"n8n-nodes-base.scheduleTrigger","position":[-180,0],"parameters":{},"typeVersion":1.2},{"id":"dec836ff-a0fb-4b6c-9ea6-e7a383343a2b","name":"Set GPT Model","type":"n8n-nodes-base.set","position":[1020,0],"parameters":{},"typeVersion":3.4},{"id":"f349a57b-0720-4ef1-8b0c-4d07c7908c73","name":"Begin Fine-tune Job","type":"n8n-nodes-base.httpRequest","position":[1300,0],"parameters":{},"typeVersion":4.2},{"id":"857dd175-1d8b-4b11-aabd-27a9ed9519a8","name":"Upload JSONL File","type":"@n8n/n8n-nodes-langchain.openAi","position":[740,0],"parameters":{},"typeVersion":1.8},{"id":"5b297840-c851-42a0-8490-6b8c2f77e6d2","name":"Create JSONL File","type":"n8n-nodes-base.code","position":[440,0],"parameters":{},"typeVersion":2},{"id":"5270eae1-1218-4ef6-b423-b4267df04c2f","name":"Check Fine-Tune Job","type":"n8n-nodes-base.httpRequest","position":[1740,0],"parameters":{},"typeVersion":4.2},{"id":"3a2349ac-836a-4145-b0f9-cf1814db5180","name":"If Succeeded","type":"n8n-nodes-base.if","position":[1920,0],"parameters":{},"typeVersion":2.2},{"id":"5ab2283c-3c25-4c4a-a786-3bb4c7c68702","name":"If Failed","type":"n8n-nodes-base.if","position":[2120,100],"parameters":{},"typeVersion":2.2},{"id":"18b2ad15-896b-48b9-a3fd-fc10214172a2","name":"Error: FAILED","type":"n8n-nodes-base.stopAndError","position":[2300,100],"parameters":{},"typeVersion":1},{"id":"992ac7d4-c889-4d5c-8359-e85f82068144","name":"Add Fine-Tuned Model to Airtable","type":"n8n-nodes-base.airtable","disabled":true,"position":[2620,80],"parameters":{},"typeVersion":2.1},{"id":"b0af9c97-b6e2-466d-9961-925685a6eb9d","name":"Add  Fine-Tuned Model to Sheet","type":"n8n-nodes-base.googleSheets","position":[2620,-120],"parameters":{},"typeVersion":4.6},{"id":"abd193e2-472b-4bee-a4d5-8d78327eebe9","name":"Get Examples from Sheet","type":"n8n-nodes-base.googleSheets","position":[120,-100],"parameters":{},"typeVersion":4.5},{"id":"cc556207-aa3f-4eaa-a8f6-1bec94c055fc","name":"Get Examples from Airtable","type":"n8n-nodes-base.airtable","disabled":true,"position":[120,120],"parameters":{},"typeVersion":2.1},{"id":"3d97f4cf-135c-49ba-b47c-43bfdf7ebb18","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-220,-280],"parameters":{"content":""},"typeVersion":1},{"id":"06bc45b5-f279-4154-b3a5-bc7690019a64","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[360,-280],"parameters":{"content":""},"typeVersion":1},{"id":"8d11924b-c641-40e7-8b0b-fee2db50a9c7","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[940,-280],"parameters":{"content":""},"typeVersion":1},{"id":"bad9fdb4-b769-48f2-9335-3b1a3a2236f5","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1500,-280],"parameters":{"content":""},"typeVersion":1},{"id":"2cce770f-eb21-4c86-8a19-16a2c0e37f2b","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[2480,-280],"parameters":{"content":""},"typeVersion":1}],"active":false,"pinData":{"Schedule Trigger":[{"json":{"Hour":"04","Year":"2025","Month":"June","Minute":"10","Second":"35","Timezone":"America/Los_Angeles (UTC-07:00)","timestamp":"2025-06-10T04:10:35.192-07:00","Day of week":"Tuesday","Day of month":"10","Readable date":"June 10th 2025, 4:10:35 am","Readable time":"4:10:35 am"}}]},"settings":{"executionOrder":"v1"},"versionId":"6bd0a799-f4a7-4907-8a14-204d023f4ae6","connections":{"Wait":{"main":[[{"node":"Check Fine-Tune Job","type":"main","index":0}]]},"If Failed":{"main":[[{"node":"Error: FAILED","type":"main","index":0}],[{"node":"Wait","type":"main","index":0}]]},"If Succeeded":{"main":[[{"node":"Add Fine-Tuned Model to Airtable","type":"main","index":0},{"node":"Add  Fine-Tuned Model to Sheet","type":"main","index":0}],[{"node":"If Failed","type":"main","index":0}]]},"Set GPT Model":{"main":[[{"node":"Begin Fine-tune Job","type":"main","index":0}]]},"Schedule Trigger":{"main":[[{"node":"Get Examples from Sheet","type":"main","index":0},{"node":"Get Examples from Airtable","type":"main","index":0}]]},"Create JSONL File":{"main":[[{"node":"Upload JSONL File","type":"main","index":0}]]},"Upload JSONL File":{"main":[[{"node":"Set GPT Model","type":"main","index":0}]]},"Begin Fine-tune Job":{"main":[[{"node":"Wait","type":"main","index":0}]]},"Check Fine-Tune Job":{"main":[[{"node":"If Succeeded","type":"main","index":0}]]},"Get Examples from Sheet":{"main":[[{"node":"Create JSONL File","type":"main","index":0}]]},"Get Examples from Airtable":{"main":[[{"node":"Create JSONL File","type":"main","index":0}]]}}}


name: Family Assistant: Schedule, Meal & Routine Management with Email & Telegram
author_name: Issam AGGOUR
author_username: devgor
nodes_used: ["n8n-nodes-base.emailSend","n8n-nodes-base.telegram","n8n-nodes-base.gmail","n8n-nodes-base.code"]
categories: []
created_at: 2025-06-10T15:06:29.333Z
updated_at: 2025-06-10T15:06:29.333Z
url: https://n8n.io/workflows/4855
scraped_at: 2025-06-19 22:49:21
description:
  The FamilyFlow Assistant is your n8n-powered 🚀 companion designed to streamline daily parenting tasks, reduce mental load, and bring a bit more organization and fun into your family life. This versatile workflow automates reminders, generates helpful ideas, and provides gentle nudges to keep your household running smoothly.

  Why FamilyFlow Assistant? 🤔
  Parenting is a demanding (and rewarding!) job. Juggling schedules, meals, routines, and remembering everything can be overwhelming. FamilyFlow Assistant aims to:

  Reduce Mental Clutter:** Offload common reminders and to-dos to an automated system.
  Enhance Organization:** Keep track of activities, appointments, and important checks.
  Spark Joy & Creativity:** Generate meal ideas, story starters, and positive thoughts.
  Promote Routine:** Help establish and maintain consistent morning and evening routines.
  Save Time:** Automate repetitive prompts and checks, freeing you up for what matters most.

  Core Features & Automations 🧩
  This workflow bundle comes packed with several independent yet complementary automations:

  📅 Daily & Weekly Organization:

  Activity & Appointment Reminders:** Get a daily heads-up on scheduled events for the family.
  Morning Routine Checklist:** Start the day right with a friendly checklist for kids (or parents!).
  Bedtime Routine Nudge:** A gentle reminder to begin the wind-down process.
  Evening “Did You Remember?” Scan:** A quick mental checklist for common end-of-day to-dos.
  Weekly “Plan Ahead” Prompt:** A Sunday reminder to review the upcoming week.
  School/Daycare Comms Check:** Prompts to check for important updates.

  💡 Inspiration & Well-being:

  Meal Idea Generator:** Never wonder “what’s for dinner?” again (or at least, less often!).
  Positive Thought / Fun Fact Sender:** A little daily dose of brightness.
  Story Starter / Quick Activity Prompt:** Spark imagination or a quick family interaction.
  Weekly Wins & Gratitude Reminder:** Encourage reflection on positive moments.

  ⏱️ Optional Helpers:

  Screen Time Break Reminder:** (Disabled by default) A nudge for offline time.

  Getting Started: Setup & Customization 🛠️
  Make FamilyFlow Assistant truly yours with these simple steps:

  Import the Workflow: Add the provided .json file to your n8n instance.
  Configure Credentials:
      Email: Set up your preferred email sending credential (e.g., SMTP, Gmail) in all “Email Send” nodes. You’ll likely use the same one for all.
  Personalize Content (Crucial!):
      Email Addresses: Update parents@example.com to your actual email(s) in all Email nodes.
      Schedules & Activities: Edit the “Define Daily Schedules” (Set node) with your family’s actual events.
      Meal Ideas: Customize the mealIdeas array in the “Generate Meal Idea” (Function node).
      Checklists & Prompts: Tailor the text/HTML in Email nodes for morning/bedtime routines, check-ins, story starters, etc., to fit your family’s style.
      Positive Thoughts/Facts: Update the lists in the “Get Positive Thought/Fact” (Function node).
  Adjust Triggers (Cron Nodes):
      Modify the “Rule” in each Cron node to set the exact time and frequency for each automation.
  Activate Automations:
      The main workflow and most automations are inactive by default. Toggle the “Active” switch ON for the entire workflow or for individual automations/nodes you wish to use.
      Remember, the “Screen Time Break Reminder” is disabled by default; enable its Email node if desired.

  How Each Automation Works (Briefly) ⚙️
  Each automation generally follows this pattern:

  TRIGGER: An event starts the flow (e.g., a scheduled time via Cron).
  PROCESS: Data is defined (e.g., list of activities, meal ideas) or generated (e.g., a random selection, a formatted message).
  RESPOND: An action is taken, typically sending an email with the relevant information or reminder.

  For instance, the “Daily Activity Reminder” uses a Cron trigger, a Set node to hold your schedule, a Function node to filter for today’s events, an IF node to check if there are any, and finally an Email node to send the reminder.

  Expanding Your Assistant 🚀
  FamilyFlow Assistant is a great starting point. Consider these ideas to extend its capabilities:

  Integrate Calendars:** Connect to Google Calendar or Outlook Calendar to fetch events dynamically.
  Use Different Notifiers:** Send messages via Telegram, WhatsApp, Slack, or push notifications.
  Smart Home Integration:** If you have smart home devices, trigger lights or announcements for routines.
  Shared To-Do Lists:** Update a shared Todoist or Microsoft To Do list.
  Interactive Input:** Use n8n forms or Telegram commands to add events or trigger specific actions.

  Requirements 📋
  An active n8n instance (self-hosted or cloud).
  Email sending credentials configured in n8n.
  A little time to customize the content to perfectly match your family’s needs!

  Embrace the flow and let your FamilyFlow Assistant help make parenting a little smoother!

workflow_json:
  {"id":"iidM8fTZl2AySmL0","meta":{"instanceId":"bfd420b2507202b96311097daac596f40dd0b52b490356dbc5c97e783dc18513","templateCredsSetupCompleted":true},"name":"FamilyFlow Assistant","tags":[],"nodes":[{"id":"c3ad02b6-47ad-492d-ac9c-2861a0c6ed66","name":"Start","type":"n8n-nodes-base.start","position":[-1120,-440],"parameters":{},"typeVersion":1},{"id":"6a091f3e-108e-4705-ac22-1b81b1153e7e","name":"Daily Morning Trigger (Weekdays)","type":"n8n-nodes-base.cron","position":[-1120,-20],"parameters":{},"typeVersion":1},{"id":"15b95fe4-68bc-49e7-ad1d-a39b97552b42","name":"If Events Today?","type":"n8n-nodes-base.if","position":[-400,-20],"parameters":{},"typeVersion":1},{"id":"5a186c22-1357-4ac0-aa0d-73f2e3865ba8","name":"Email Schedule Reminder","type":"n8n-nodes-base.emailSend","position":[-160,-40],"parameters":{},"typeVersion":1},{"id":"9754ee5b-052b-4e2b-92a5-8e5f4b8337e1","name":"Email Morning Checklist","type":"n8n-nodes-base.emailSend","position":[-160,140],"parameters":{},"typeVersion":1},{"id":"a46dcc63-1d6d-4b25-9e74-b66fe7a5cde1","name":"Email Meal Idea","type":"n8n-nodes-base.emailSend","position":[-160,280],"parameters":{},"typeVersion":1},{"id":"7007a291-7c85-4626-a3eb-de686cacf5c2","name":"Daily Evening Trigger","type":"n8n-nodes-base.cron","position":[-1120,420],"parameters":{},"typeVersion":1},{"id":"72bdaae3-fd67-464f-9d96-2f6908de044c","name":"Email Bedtime Reminder","type":"n8n-nodes-base.emailSend","position":[-160,420],"parameters":{},"typeVersion":1},{"id":"2a783d61-bbd4-4f53-9cb5-36d3a52ddc74","name":"Weekly Planning Trigger (Sunday PM)","type":"n8n-nodes-base.cron","position":[-1120,560],"parameters":{},"typeVersion":1},{"id":"1f74925e-d4e7-4cd9-9e45-495e2dfe758c","name":"Email Weekly Plan Prompt","type":"n8n-nodes-base.emailSend","position":[-160,560],"parameters":{},"typeVersion":1},{"id":"74f81526-5875-4c9d-b300-1224fb9176d9","name":"Screen Time Break Trigger (Optional)","type":"n8n-nodes-base.cron","position":[-1120,720],"parameters":{},"typeVersion":1},{"id":"88443345-58d7-44fb-ac06-24178edcd170","name":"Email Screen Break Reminder","type":"n8n-nodes-base.emailSend","position":[-160,720],"parameters":{},"typeVersion":1},{"id":"8120077c-e454-4de4-ba19-eca66f8a59a1","name":"Email Positive Thought/Fact","type":"n8n-nodes-base.emailSend","position":[-160,880],"parameters":{},"typeVersion":1},{"id":"db509d61-1da8-47e4-a1e0-ffa046d1da09","name":"Telegram Trigger","type":"n8n-nodes-base.telegramTrigger","position":[-1120,-300],"webhookId":"8011832f-eb93-45b0-b127-a2342642619f","parameters":{},"typeVersion":1.2},{"id":"79f5d86c-f2e8-4d70-b0c9-977c02b04a91","name":"Trigger: School/Daycare Comms Check","type":"n8n-nodes-base.cron","position":[-1120,1040],"parameters":{},"typeVersion":1},{"id":"b79158a0-b34e-480e-9a0e-6a6b9b989f3d","name":"Email: School Comms Reminder","type":"n8n-nodes-base.emailSend","position":[-160,1040],"parameters":{},"typeVersion":1},{"id":"1d00cab9-0428-4993-9f5b-5719f25ea9f5","name":"Trigger: Weekly Wins/Gratitude","type":"n8n-nodes-base.cron","position":[-1120,1200],"parameters":{},"typeVersion":1},{"id":"441b6e48-b5c1-4fde-a647-a0978d431cdf","name":"Email: Wins/Gratitude Reminder","type":"n8n-nodes-base.emailSend","position":[-160,1200],"parameters":{},"typeVersion":1},{"id":"1d702d2b-ef45-4ef7-9a73-a757d19b1a94","name":"Trigger: Daily Evening Check-in","type":"n8n-nodes-base.cron","position":[-1120,1360],"parameters":{},"typeVersion":1},{"id":"23c8836f-008f-4b6d-8f11-52336ff913bf","name":"Email: Evening Check-in","type":"n8n-nodes-base.emailSend","position":[-160,1360],"parameters":{},"typeVersion":1},{"id":"bebecc7a-037e-4955-82f3-52f75c505fc2","name":"Format Check-in Message","type":"n8n-nodes-base.code","position":[-400,1360],"parameters":{},"typeVersion":2},{"id":"e109049e-c898-4633-9d81-61aeca9d6f2e","name":"Get Positive Thought/Fact1","type":"n8n-nodes-base.code","position":[-640,880],"parameters":{},"typeVersion":2},{"id":"f0d5b249-c504-48ed-80b6-64a5fada9c89","name":"Screen Time Break Trigger (Optional)1","type":"n8n-nodes-base.cron","position":[-1120,880],"parameters":{},"typeVersion":1},{"id":"ec194efa-e7e3-441f-bd76-1c7963890e7d","name":"Daily Meal Idea","type":"n8n-nodes-base.cron","position":[-1120,280],"parameters":{},"typeVersion":1},{"id":"cdec12bb-f961-43c0-a5ad-ba9fecf6e011","name":"Daily Meal Idea1","type":"n8n-nodes-base.cron","position":[-1120,140],"parameters":{},"typeVersion":1},{"id":"10bcd7d0-087f-4c22-a185-75b3956b2a98","name":"Code","type":"n8n-nodes-base.code","position":[-640,-440],"parameters":{},"typeVersion":2},{"id":"9d79706d-7aa0-4968-8210-b3bf63f75f30","name":"Check Today's Schedule","type":"n8n-nodes-base.code","position":[-640,-20],"parameters":{},"typeVersion":2},{"id":"0c90fa31-ae58-4061-bd7b-cb2548224e98","name":"Generate Meal Idea","type":"n8n-nodes-base.code","position":[-640,280],"parameters":{},"typeVersion":2},{"id":"738f49bc-087e-403d-aa7a-f1e04323832e","name":"Define Daily Schedules","type":"n8n-nodes-base.set","position":[-860,-20],"parameters":{},"typeVersion":3.4},{"id":"013827e5-9be4-4232-900d-464880152308","name":"Define Check-in Items","type":"n8n-nodes-base.set","position":[-780,1360],"parameters":{},"typeVersion":3.4},{"id":"326affff-fe87-4b39-915c-4496028799eb","name":"Edit Fields","type":"n8n-nodes-base.set","position":[-640,-300],"parameters":{},"typeVersion":3.4},{"id":"83a24812-6692-4583-8183-0c8360a78448","name":"Telegram","type":"n8n-nodes-base.telegram","position":[-160,-300],"webhookId":"4ed6f009-10f4-45f3-b264-a2ef808d0a92","parameters":{},"typeVersion":1.2},{"id":"1db0ca81-dc11-4a42-a6bf-f3ae312fe371","name":"Gmail","type":"n8n-nodes-base.gmail","position":[-160,-440],"webhookId":"1c602240-fbcc-4caf-8c87-d38a75497f14","parameters":{},"typeVersion":2.1},{"id":"b0d3a185-40c7-4a97-8fe4-34bc9a167ab6","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-1200,-820],"parameters":{"content":""},"typeVersion":1},{"id":"efe033c3-8333-4e49-ac46-f3435b60abbe","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-760,-820],"parameters":{"content":""},"typeVersion":1},{"id":"0b574e6a-7ab9-4e65-9593-00c9c8393eba","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-300,-820],"parameters":{"content":""},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"9f432720-82ca-474e-810b-a1e6f648d99f","connections":{"Code":{"main":[[{"node":"Gmail","type":"main","index":0}]]},"Start":{"main":[[{"node":"Code","type":"main","index":0}]]},"Edit Fields":{"main":[[{"node":"Telegram","type":"main","index":0}]]},"Daily Meal Idea":{"main":[[{"node":"Generate Meal Idea","type":"main","index":0}]]},"Daily Meal Idea1":{"main":[[{"node":"Email Morning Checklist","type":"main","index":0}]]},"If Events Today?":{"main":[[{"node":"Email Schedule Reminder","type":"main","index":0}]]},"Telegram Trigger":{"main":[[{"node":"Edit Fields","type":"main","index":0}]]},"Generate Meal Idea":{"main":[[{"node":"Email Meal Idea","type":"main","index":0}]]},"Daily Evening Trigger":{"main":[[{"node":"Email Bedtime Reminder","type":"main","index":0}]]},"Define Check-in Items":{"main":[[{"node":"Format Check-in Message","type":"main","index":0}]]},"Check Today's Schedule":{"main":[[{"node":"If Events Today?","type":"main","index":0}]]},"Define Daily Schedules":{"main":[[{"node":"Check Today's Schedule","type":"main","index":0}]]},"Format Check-in Message":{"main":[[{"node":"Email: Evening Check-in","type":"main","index":0}]]},"Get Positive Thought/Fact1":{"main":[[{"node":"Email Positive Thought/Fact","type":"main","index":0}]]},"Trigger: Weekly Wins/Gratitude":{"main":[[{"node":"Email: Wins/Gratitude Reminder","type":"main","index":0}]]},"Trigger: Daily Evening Check-in":{"main":[[{"node":"Define Check-in Items","type":"main","index":0}]]},"Daily Morning Trigger (Weekdays)":{"main":[[{"node":"Define Daily Schedules","type":"main","index":0}]]},"Trigger: School/Daycare Comms Check":{"main":[[{"node":"Email: School Comms Reminder","type":"main","index":0}]]},"Weekly Planning Trigger (Sunday PM)":{"main":[[{"node":"Email Weekly Plan Prompt","type":"main","index":0}]]},"Screen Time Break Trigger (Optional)":{"main":[[{"node":"Email Screen Break Reminder","type":"main","index":0}]]},"Screen Time Break Trigger (Optional)1":{"main":[[{"node":"Get Positive Thought/Fact1","type":"main","index":0}]]}}}


