ChatGPTSalesFinding leadsAI score · 76/100AI-assisted edit · no obvious prompt-injection riskn8n.io

Auto-Generate Lead Research Report After Booking

Cal.com trigger → Google Sheets LinkedIn lookup → Relevance AI scrape + Perplexity research → OpenAI profile & pain points → HTML report → Gmail delivery

Some experienceStepsWorkflowPrompt
Who
Sales reps, consultants, and founders who need pre-meeting prospect intelligence
You get
Receive a formatted HTML email report minutes after a booking, with LinkedIn profile, company info, recent posts, news context, pain points, and high-ROI automation suggestions
You need
n8n · gmail · google-sheets · perplexity · relevance-ai

Constraints

Requires an n8n instance; configure Cal.com (or alternative booking tool) trigger, Google Sheets OAuth2, Relevance AI HTTP Header Auth, Perplexity API, OpenAI API, and Gmail OAuth2 credentials. Multiple Google Sheets nodes in the template should be merged into your actual database. The Filter node's default condition needs replacement.

What they did

This n8n template demonstrates a complete workflow: when someone books a meeting via Cal.com, the system looks up their LinkedIn URL from a Google Sheets database, scrapes their public profile, posts, education, and experience via Relevance AI, and simultaneously runs a Perplexity deep-dive on their company. The scraped data is formatted into HTML fragments by Code nodes, then fed to two OpenAI nodes that generate a personal/company profile and pain-point analysis with high-ROI suggestions. Finally, everything is assembled into a complete HTML report and sent via Gmail.

How it went

Expected outcome per source description (author_report): within about 2 minutes of a booking, you receive a formatted research email in your inbox containing their role, company, latest posts, what their business does, recent news and context from Perplexity, predicted pain points, and how you might help—so you show up to the call prepped and ready.

Worth knowing

1. Prompts hardcode the author's company name "Built by Abdul" and "Kamexa"; these must be replaced with your own business description or the generated content will reference the wrong company. 2. The template contains 4 Google Sheets nodes pointing to different spreadsheets; in practice these should be merged into your single customer database. 3. The Filter node defaults to filtering [email protected]; update or remove this condition. 4. The Relevance AI endpoint is a project-specific URL (includes project ID), not a generic API—create your own studio in Relevance AI and replace the endpoint. 5. Prompts reference TrustPilot reviews as an input, but no TrustPilot node exists in workflow.json; this input will not be automatically fetched in the current template. 6. The o1-mini model selection should be verified for availability and cost; gpt-4o or similar can be substituted. 7. No actual execution logs or third-party validation are provided by the source; the effect description is author-reported.

n8n workflow template

Structure checked · Not run-tested

Use “Import from File” in n8n, or copy the JSON and paste it into the editor. Connect your own accounts, then try test data. The template is inactive by default.

Setup and test checklist

Credentials to connect

  • Person + Company Profile node: connect OpenAI API credentials.
  • Pain Points + Solutions node: connect OpenAI API credentials.
  • Email Report node: connect Gmail OAuth2 credentials.
  • Cal.com Trigger node: connect calApi credentials.
  • Perplexity node: connect Perplexity API credentials.
  • Scrape Profiles + Posts - Relevance AI node: connect HTTP Header Auth credentials.
  • Google Sheets node: connect Google Sheets OAuth2 credentials.
  • Google Sheets1 node: connect Google Sheets OAuth2 credentials.
  • Google Sheets2 node: connect Google Sheets OAuth2 credentials.
  • Google Sheets3 node: connect Google Sheets OAuth2 credentials.

Configuration to replace

  • Source template is n8n public workflow #6535 (~27 nodes). Keep inactive after import; verify triggers, expressions and external API endpoints.
  • Sticky-note guidance is informational; replace placeholders with your own accounts, sheet schemas or channel IDs.

Test input and expected output

  • Manually run the main path once in a test workspace and confirm credentialed nodes authenticate without errors.
  • Drive one synthetic/redacted sample through and check output fields and downstream writes before enabling in production.

Template changes

  • Author credential bindings, webhookId and execution data are removed; the workflow is inactive. Nodes, connections and original prompts are preserved. Not run-tested in n8n.
  • No business-logic edits; verify keys, quotas and privacy compliance before use.

Template retrieved: 2026-10-24

Steps

  1. Configure trigger and database connections

    After importing the template, connect the Cal.com Trigger (or replace with Calendly/SavvyCal) and set it to listen for BOOKING_CREATED events. Configure Google Sheets node(s) to query your actual customer database containing email and LinkedIn URL fields. Merge the multiple lookup nodes into one or point them to the same sheet. Change the Filter node's rightValue from [email protected] to your actual test email or remove the filter. [First-test safety] Keep the workflow inactive after import; before the first test, temporarily disconnect the Email Report node input, or set sendTo to a test mailbox and keep sending disabled/unactivated, so a real booking cannot auto-email or burn Relevance AI / Perplexity API quota.

  2. Scrape and format LinkedIn data

    Configure the Scrape Profiles + Posts - Relevance AI HTTP Request node: replace the URL with your own Relevance AI project endpoint (the template uses https://api-bcbe5a.stack.tryrelevance.com/...), and provide your API key in the HTTP Header Auth credential. This node sends a POST request with jsonBody {"linkedin_url":"{{ $json.profileUrl }}","last_x_days":30}. Downstream Posts, Experiences, and Education Code nodes automatically transform the response into HTML fragments. Node request body: ```json ={"linkedin_url":"{{ $json.profileUrl }}","last_x_days":30} ``` Node code: ```js const input = $node["Scrape Profiles + Posts - Relevance AI"].json; // Getting posts from output, then fallback to top-level. const posts = (input.output && input.output.last_30_days_posts_transformed) || input.last_30_days_posts_transformed || []; // Build HTML for each LinkedIn post let postsHTML = ''; if (Array.isArray(posts)) { posts.forEach(post => { postsHTML += `<div class="linkedin-post" style="border:1px solid #ddd; padding:10px; margin-bottom:10px;"> <p>${post.user_post}</p> <p><em>Posted on: ${post.posted}</em></p> </div>`; }); } // Return only the generated HTML return [{ json: { postsHTML } }]; ``` Node code: ```js // Get the input data from the first item const input = $node["Scrape Profiles + Posts - Relevance AI"].json; // Navigate to the experiences array within the "output" object const experiences = input.linkedin_profile_details_data?.experiences || []; // Build the HTML table rows string let htmlRows = ''; experiences.forEach(exp => { htmlRows += `<tr> <td>${exp.company}</td> <td>${exp.title}</td> <td>${exp.date_range}</td> <td>${exp.location}</td> </tr>`; }); // Return a new object that only contains the experiencesTable field return [{ json: { experiencesTable: htmlRows } }]; ``` Node code: ```js // Get the input data from the first item const input = $node["Scrape Profiles + Posts - Relevance AI"].json; // Navigate to the educations array in the output object const educations = input.linkedin_profile_details_data?.educations || []; // Build the HTML table rows for education let educationRows = ''; educations.forEach(edu => { educationRows += `<tr> <td>${edu.school}</td> <td>${edu.degree}</td> <td>${edu.field_of_study}</td> </tr>`; }); // Return a new object that only contains the educationTable key return [{ json: { educationTable: educationRows } }]; ```

  3. Run deep web research

    Configure the Perplexity node: select sonar-pro model and provide Perplexity API credentials. The system message sets the researcher role; the user message passes the company name and website URL extracted from LinkedIn. The downstream Citations Code node converts the Perplexity citations array into an HTML link list. Node code: ```js // Retrieve the JSON from the previous node const input = items[0].json; // Extract the citations array; default to an empty array if not present const citations = input.citations || []; // Build an HTML unordered list for the citations let citationsHTML = '<ul>'; if (Array.isArray(citations)) { citations.forEach(citation => { citationsHTML += `<li><a href="${citation}" target="_blank">${citation}</a></li>`; }); } citationsHTML += '</ul>'; // Return a new JSON object containing the generated HTML snippet return [{ json: { citationsHTML } }]; ```

    Execution prompt · Source text。Perplexity node messages.message[0].content (system role)

    =You are a researcher in a business development team. Your job is to find as much research as you can about the prospect company. You must ensure your research is for the correct company and is highly accurate. Your research must always include what the prospect company does.

    Execution prompt · Source text。Perplexity node messages.message[1].content (user role)

    =
    Find as much info as you can about {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.company }}. }} This is their website URL: {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.company_website }}
  4. Generate person and company profile

    Configure the Person + Company Profile OpenAI node: select o1-mini model (or substitute an available GPT model) and connect OpenAI API credentials. This node receives LinkedIn bio, last 30 days of posts (transformed by the Posts node), and Perplexity research results, then generates an HTML fragment containing personal profile, interests, unique facts, and company profile.

    Execution prompt · Source text。Person + Company Profile OpenAI node messages.values[0].content field

    =You are part of the business development team at Built by Abdul which is an AI Automation Agency.
    
    When a new leads book a consultation with Built by Abdul, your team researches the leads and provides the research + extracted insights to the consultants so they can read it prior to the consult. 
    
    Your job is to create the following sections from the research:
    
    - Personal Profile: The personal profile is a one paragraph summary of the person (lead) extracted from researching their LinkedIn profile.
    - Interests: In this section you must identify a few of the leads interests from their most recent LinkedIn posts + their LinkedIn profile. 
    - Unique Facts: In this section you must extract at least 2 unique facts about the lead that tells them you've really put time to research who they are. These facts should be things that are unique to the lead and out of the ordinary.
    - Company Profile: The company profile is a one paragraph summary of the company the person represents, extracted from researching their company LinkedIn profile and available information on the web. 
    
    Your output must be in HTML, following this format: 
    
    Person Profile (Heading 2)
    [Details]
    
    Company Profile (Heading 2)
    [Details]
    
    Interests (Heading 2)
    [List of interests in dot point format]
    
    Unique Facts (Heading 2)
    [List of unique facts in dot point format]
    
    
    - Don't wrap the output in ```html``` since the output will go into the middle of another HTML document. Just make sure its in HTML language.
    
    Create this output for the following research: 
    
    LinkedIn Profile About:
    {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.about }}
    
    Most Recent LinkedIn Posts: 
    {{ $('Scrape Profiles + Posts - Relevance AI').item.json.last_30_days_posts_transformed.toJsonString() }}
    
    Web Research: 
    {{ $('Perplexity').last().json.choices[0].message.content }}
  5. Generate pain points and high-ROI suggestions

    Configure the Pain Points + Solutions OpenAI node: also uses o1-mini model. This node receives the profile summary from the previous step and Perplexity company research, then outputs an HTML fragment with a pain-point evidence table and 5 highest-ROI automation opportunities. Note: replace "Built by Abdul" and "Kamexa" in the prompt with your actual company and service names.

    Execution prompt · Source text。Pain Points + Solutions OpenAI node messages.values[0].content field

    =You are part of the business development team at Built by Abdul which is an AI Automation agency that provides the following services: 
    
    -AI-powered personalized lead generation systems
    -Automated ClickUp CRMs and project management workflows
    -AI Content agents that repurpose and schedule high-volume content
    -Client onboarding automations (proposals, forms, contracts, etc.)
    -Other AI workflows that save founders dozens of hours per month
    
    Built by Abdul's consultants are the first point of contact for a new lead. So when a new lead is interested in their solutions, they book a free call with their consultants. The consultants are then responsible for exploring the highest ROI opportunities for automation.
    
    Once a call is booked, your team does in depth research on the lead so that the consultants can read through it in preparation for the consultation. 
    
    As part of the business development team you are provided with the following research: 
    
    - LinkedIn Profile: This is the result of scraping the leads LinkedIn profile. This will give you the leads bio, experiences, education and company description.
    - LinkedIn Posts: This gives you the leads LinkedIn posts over the past 30 days. 
    - Company Google Search: This gives you the research found from searching the leads company on Google and their website. 
    - Reviews: This gives you the most recent bad reviews the leads company received on TrustPilot.
    
    
    Your job is to analyse the research and extract following information: 
    
    - Pain Points: By looking through the companies negative reviews and also considering their line of business and the leads position in the company, you must identify the biggest pain points the leads company could be facing. 
    - Solutions to Pain Points: In this section you must come up with solutions Built by Abdul can offer to solve each of the pain points completely. 
    - Highest ROI Opportunities: Considering the info you have about the lead and his company, you must come up with the 5 highest ROI opportunities that Built by Abdul can offer them. These automations have to be realisitic, yet extremely high ROI. Sort them in order of best opportunity at the top of the list.  
    
    The insights you extract must be in HTML format as they will be going in the middle of a HTML document. 
    
    Please use the following output format: 
    
    Opportunities (Heading 1)
    
    Pain Points and Solutions: (Heading 2)
    [Table with 3 columns: 
    1. Pain Point: Explains the pain point theyre facing. 
    2. Evidence: Explains why we think this is the case. 
    3. Solution: Explains the solution to the pain point by Kamexa.
    Each row is a new pain point.]
    
    Opportunities: (Heading 2)
    [5 Highest ROI automation opportunities for the leads company sorted with the best solution at the top. This must be in dotpoint format:
    - Opportunity#1 Name: Details
    - Opportunity#2 Name: Details
    ...
    
    - Don't wrap the output in ```html``` since the output will go into the middle of another HTML document.
    
    Someone just booked a call. Here's the research your team found. Create the output as per the above requirements: 
    
    LinkedIn Profile Scraped Summary in HTML format: 
    {{ $('Person + Company Profile').last().json.message.content }}
    
    Web Research Results for Leads Company: 
    {{ $('Perplexity').last().json.choices[0].message.content }}
  6. Assemble HTML report

    The Create HTML Report node uses the HTML template engine to combine all upstream outputs (profile, pain points, LinkedIn details, education, experience, posts, research, citations) into a complete HTML document. The template contains CSS styling and n8n expression syntax referencing each upstream node's json output. Verify that all upstream node names match the $node['NodeName'] references in the template. Email HTML template: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Consultant Research Report</title> <style> body { font-family: Arial, sans-serif; margin: 20px; line-height: 1.6; color: #333; } h1, h2, h3 { color: #222; } .section { margin-bottom: 40px; } .profile-details p { margin: 5px 0; } table { width: 100%; border-collapse: collapse; margin-top: 10px; } th, td { border: 1px solid #ddd; padding: 8px; vertical-align: top; } th { background-color: #f2f2f2; } .card { border: 1px solid #ddd; padding: 10px; margin-bottom: 10px; border-radius: 4px; } a { color: #1a0dab; text-decoration: none; } a:hover { text-decoration: underline; } /* New styles for the header images container */ .header-images { display: flex; margin-bottom: 20px; } .header-images img { width: 50%; height: auto; max-width: 300px; } </style> </head> <body> <!-- Header Images --> <div class="header-images"> <img src="{{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.profile_image_url }}" alt="Profile Picture"> <img src="{{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.company_logo_url }}" alt="Company Logo"> </div> <!-- Analysis & Key Facts --> <div class="section" id="analysis"> <h1>Analysis & Key Facts</h1> {{ $('Person + Company Profile').last().json.message.content }} {{ $('Pain Points + Solutions').last().json.message.content }} </div> <!-- Detailed Research Report --> <div class="section" id="research-report"> <h1>Research Report</h1> <!-- LinkedIn Profile Details --> <div id="linkedin-profile" class="profile-details"> <h2>LinkedIn Profile Details</h2> <p><strong>Name:</strong> {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.full_name }}</p> <p><strong>Headline:</strong> {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.headline }}</p> <p><strong>Location:</strong> {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.location }}</p> <p><strong>About:</strong> {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.about }}</p> <p><strong>City:</strong> {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.city }}</p> <p><strong>Country:</strong> {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.country }}</p> <p><strong>Job Title:</strong> {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.job_title }}</p> <p><strong>Company:</strong> {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.company }}</p> <p><strong>Company Description:</strong> {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.company_description }}</p> <p> <strong>Company Website:</strong> <a href="{{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.company_website }}"> {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.company_website }} </a> </p> <p><strong>Industry:</strong> {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.company_industry }}</p> <p> <strong>LinkedIn URL:</strong> <a href="{{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.linkedin_url }}"> {{ $('Scrape Profiles + Posts - Relevance AI').item.json.linkedin_profile_details_data.linkedin_url }} </a> </p> </div> <!-- Education --> <div id="education"> <h2>Education</h2> <table> <thead> <tr> <th>School</th> <th>Degree</th> <th>Field of Study</th> </tr> </thead> <tbody> {{ $node["Education"].json.educationTable }} </tbody> </table> </div> <!-- Experience --> <div id="experience"> <h2>Experience</h2> <table> <thead> <tr> <th>Company</th> <th>Title</th> <th>Date Range</th> <th>Location</th> </tr> </thead> <tbody> {{ $node["Experiences"].json.experiencesTable }} </tbody> </table> </div> <!-- Recent LinkedIn Posts --> <div id="linkedin-posts"> <h2>Recent LinkedIn Posts</h2> {{ $node["Posts"].json.postsHTML }} </div> <!-- Google Research Analysis --> <div id="google-research"> <h2>Google Research Analysis</h2> <p>{{ $node["Perplexity"].json.choices[0].message.content.removeMarkdown().removeMarkdown() }}</p> </div> <!-- Citations --> <div id="citations"> <h2>Citations</h2> {{ $node["Citations"].json.citationsHTML }} </div> </div> </body> </html> ```

  7. Send email report

    Configure the Email Report Gmail node: connect Gmail OAuth2 credentials, change sendTo from [email protected] to your receiving email. The subject uses an n8n expression to dynamically insert the prospect's full name, and the message references the upstream HTML node's output. Manually test once before enabling auto-send. [First-test safety] Before the first test, set Email Report sendTo to a test inbox, or temporarily disconnect Email Report from Create HTML Report, or gate sends to the test address only.

Prompt you can copy

Setup guidance · Editorial suggestion。Hand to setup assistant; confirm inputs and permissions first

This block is the prompt. Ads are never placed here.

After importing, prioritize replacing all credentials, updating the Filter email, merging multiple Google Sheets into your database, and swapping "Built by Abdul/Kamexa" in prompts for your company name

Source

Lead research report emails · abdulmir · n8n.io · 2025-07-27

Comments & feedback

Tried this method? Share results, problems or improvements. Comments appear after moderation. Please avoid sensitive information.

Loading…

    Related