Tutorial

How to Fix Outreach Personalization with n8n Search

Improve cold outreach personalization in n8n by enriching leads with live search data. Pull recent news, blog posts, and company updates for each prospect.

Fix weak outreach personalization in n8n by adding a search enrichment step that pulls recent prospect activity before email generation. Generic personalization like using first names and company names gets ignored. Effective personalization references something specific: a recent blog post, a funding announcement, a product launch, or a conference talk. By querying the search API for each prospect before drafting the email, your n8n workflow can generate genuinely personalized openers that reference real, recent events.

Prerequisites

  • n8n instance running (self-hosted or n8n Cloud)
  • A Scavio API key from scavio.dev
  • A lead list with names and companies
  • An email sending node configured in n8n

Walkthrough

Step 1: Search for prospect activity

Query for the prospect's name and company to find recent public activity.

Python
import os, requests

API_KEY = os.environ['SCAVIO_API_KEY']

def find_prospect_activity(name: str, company: str) -> list:
    resp = requests.post('https://api.scavio.dev/api/v1/search',
        headers={'x-api-key': API_KEY},
        json={'platform': 'google', 'query': f'{name} {company} 2026'}, timeout=15)
    results = resp.json().get('organic_results', [])
    activities = []
    for r in results[:5]:
        activities.append({
            'title': r.get('title', ''),
            'snippet': r.get('snippet', ''),
            'url': r.get('link', ''),
            'type': classify_activity(r),
        })
    return activities

def classify_activity(result: dict) -> str:
    title = (result.get('title', '') + result.get('snippet', '')).lower()
    if any(w in title for w in ['blog', 'article', 'wrote', 'published']):
        return 'content'
    if any(w in title for w in ['spoke', 'conference', 'keynote', 'panel']):
        return 'speaking'
    if any(w in title for w in ['raised', 'funding', 'series', 'launch']):
        return 'news'
    return 'mention'

activities = find_prospect_activity('Jane Smith', 'Acme Corp')
for a in activities:
    print(f"[{a['type']}] {a['title'][:60]}")

Step 2: Search company news

Pull recent company news to find relevant events for personalization.

Python
def get_company_news(company: str) -> list:
    resp = requests.post('https://api.scavio.dev/api/v1/search',
        headers={'x-api-key': API_KEY},
        json={'platform': 'google', 'query': f'{company} news announcement 2026'}, timeout=15)
    results = resp.json().get('organic_results', [])
    return [{
        'headline': r.get('title', ''),
        'snippet': r.get('snippet', '')[:150],
        'url': r.get('link', ''),
    } for r in results[:3]]

news = get_company_news('Acme Corp')
for n in news:
    print(f"  {n['headline'][:60]}")

Step 3: Select best personalization hook

Rank the discovered activities and news items to pick the strongest personalization angle.

Python
def select_hook(activities: list, news: list) -> dict:
    # Prioritize: content > speaking > news > mention
    priority = {'content': 1, 'speaking': 2, 'news': 3, 'mention': 4}
    sorted_activities = sorted(activities, key=lambda a: priority.get(a['type'], 5))
    if sorted_activities:
        best = sorted_activities[0]
        return {
            'type': best['type'],
            'reference': best['title'],
            'url': best['url'],
            'snippet': best['snippet'][:100],
        }
    if news:
        return {
            'type': 'company_news',
            'reference': news[0]['headline'],
            'url': news[0]['url'],
            'snippet': news[0]['snippet'][:100],
        }
    return {'type': 'none', 'reference': '', 'url': '', 'snippet': ''}

hook = select_hook(activities, news)
print(f"Best hook: [{hook['type']}] {hook['reference'][:60]}")

Step 4: Generate personalized opener

Create an email opener that references the specific activity or news item found.

Python
def personalized_opener(name: str, company: str, hook: dict) -> str:
    first_name = name.split()[0] if name else 'there'
    if hook['type'] == 'content':
        return f"Hi {first_name}, I came across your piece \"{hook['reference'][:50]}\" and it resonated with something we have been working on."
    if hook['type'] == 'speaking':
        return f"Hi {first_name}, I noticed your talk at {hook['reference'][:40]} and wanted to connect."
    if hook['type'] in ('news', 'company_news'):
        return f"Hi {first_name}, saw the news about {company} - {hook['reference'][:40]}. Congrats on the milestone."
    return f"Hi {first_name}, I have been following {company}'s work and wanted to reach out."

opener = personalized_opener('Jane Smith', 'Acme Corp', hook)
print(opener)

Step 5: Batch enrich lead list

Process an entire lead list and output personalized openers for each.

Python
import time

def enrich_leads(leads: list) -> list:
    enriched = []
    for lead in leads:
        activities = find_prospect_activity(lead['name'], lead['company'])
        news = get_company_news(lead['company'])
        hook = select_hook(activities, news)
        opener = personalized_opener(lead['name'], lead['company'], hook)
        enriched.append({
            **lead,
            'hook_type': hook['type'],
            'hook_reference': hook['reference'][:80],
            'personalized_opener': opener,
        })
        print(f"{lead['name']}: [{hook['type']}] {hook['reference'][:40]}")
        time.sleep(0.5)
    return enriched

test_leads = [
    {'name': 'Jane Smith', 'company': 'Acme Corp', 'email': 'jane@acme.com'},
    {'name': 'John Doe', 'company': 'Beta Inc', 'email': 'john@beta.com'},
]
results = enrich_leads(test_leads)

Python Example

Python
import requests, os
H = {'x-api-key': os.environ['SCAVIO_API_KEY']}

def personalize(name, company):
    data = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
        json={'platform': 'google', 'query': f'{name} {company} 2026'}).json()
    top = data.get('organic_results', [{}])[0]
    return f"Re: {top.get('title', 'your recent work')[:50]}"

print(personalize('Jane Smith', 'Acme Corp'))

JavaScript Example

JavaScript
const H = {'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json'};
async function personalize(name, company) {
  const r = await fetch('https://api.scavio.dev/api/v1/search', {
    method: 'POST', headers: H,
    body: JSON.stringify({platform: 'google', query: `${name} ${company} 2026`})
  });
  const top = ((await r.json()).organic_results || [{}])[0];
  return `Re: ${(top.title || 'your recent work').slice(0, 50)}`;
}
personalize('Jane Smith', 'Acme Corp').then(console.log);

Expected Output

JSON
An n8n-compatible outreach personalization pipeline that enriches each lead with real prospect activity and company news, generating specific personalized email openers.

Related Tutorials

Frequently Asked Questions

Most developers complete this tutorial in 15 to 30 minutes. You will need a Scavio API key (free tier works) and a working Python or JavaScript environment.

n8n instance running (self-hosted or n8n Cloud). A Scavio API key from scavio.dev. A lead list with names and companies. An email sending node configured in n8n. A Scavio API key gives you 250 free credits per month.

Yes. The free tier includes 250 credits per month, which is more than enough to complete this tutorial and prototype a working solution.

Scavio has a native LangChain package (langchain-scavio), an MCP server, and a plain REST API that works with any HTTP client. This tutorial uses the raw REST API, but you can adapt to your framework of choice.

Start Building

Improve cold outreach personalization in n8n by enriching leads with live search data. Pull recent news, blog posts, and company updates for each prospect.