Tutorial: Automação de Outreach para Influencers no LinkedIn
Aprenda a automatizar todo o processo de descoberta, qualificação e contato com influencers e parceiros em potencial no LinkedIn, incluindo follow-up inteligente e tracking de respostas.
O Que Você Vai Construir
Um sistema completo de influencer outreach que: 1. Busca influencers baseado em critérios (nicho, seguidores, engajamento) 2. Enriquece perfis com dados adicionais 3. Qualifica e pontua automaticamente 4. Envia mensagens personalizadas de conexão 5. Faz follow-up automático em sequências 6. Rastreia respostas e engajamento 7. Organiza pipeline no CRM
Tempo estimado: 50 minutos Nível: Intermediário Impacto esperado: 10x mais outreach com mesma equipe, +40% taxa de resposta
O Que Você Vai Aprender
- Integração com LinkedIn via PhantomBuster ou Apify
- Web scraping ético e compliant
- Qualificação automática de leads
- Personalização em escala
- Sequências de follow-up
- Pipeline management
Pré-requisitos
- ✅ Conta LinkedIn Sales Navigator (recomendado) ou Premium
- ✅ PhantomBuster ou Apify account
- ✅ CRM (HubSpot, Pipedrive, ou similar)
- ✅ PostgreSQL
Parte 1: Estrutura de Dados
CREATE TABLE influencers (
id SERIAL PRIMARY KEY,
linkedin_url VARCHAR(500) UNIQUE NOT NULL,
full_name VARCHAR(255),
headline VARCHAR(500),
location VARCHAR(255),
-- Métricas
followers_count INT,
connections_count INT,
posts_per_week INT,
avg_engagement_rate DECIMAL(5,2),
-- Qualificação
relevance_score INT DEFAULT 0,
quality_score INT DEFAULT 0,
total_score INT DEFAULT 0,
tier VARCHAR(20), -- A, B, C
-- Enriquecimento
company VARCHAR(255),
job_title VARCHAR(255),
industry VARCHAR(100),
topics TEXT[],
recent_posts JSONB,
email VARCHAR(255),
phone VARCHAR(50),
-- Outreach
status VARCHAR(50) DEFAULT 'new', -- new, contacted, responded, partnership, declined
outreach_stage INT DEFAULT 0,
first_contact_at TIMESTAMP,
last_contact_at TIMESTAMP,
responded_at TIMESTAMP,
-- CRM
crm_id VARCHAR(255),
assigned_to VARCHAR(255),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE outreach_messages (
id SERIAL PRIMARY KEY,
influencer_id INT REFERENCES influencers(id),
sequence_stage INT,
message_type VARCHAR(50), -- connection_request, message, follow_up
subject VARCHAR(500),
content TEXT,
sent_at TIMESTAMP,
read_at TIMESTAMP,
replied_at TIMESTAMP,
reply_content TEXT,
metadata JSONB
);
CREATE INDEX idx_influencers_status ON influencers(status);
CREATE INDEX idx_influencers_score ON influencers(total_score DESC);
Parte 2: Descoberta de Influencers
2.1. Buscar no LinkedIn (PhantomBuster)
// HTTP Request: "Buscar Influencers no LinkedIn"
{
"method": "POST",
"url": "https://api.phantombuster.com/api/v2/agents/launch",
"headers": {
"X-Phantombuster-Key": "{{ $credentials.phantombuster.apiKey }}"
},
"body": {
"id": "{{ $vars.linkedinSearchAgentId }}",
"argument": {
"sessionCookie": "{{ $credentials.linkedin.sessionCookie }}",
"searches": [
"https://www.linkedin.com/search/results/people/?keywords=marketing%20automation&network=%5B%22S%22%5D",
"https://www.linkedin.com/search/results/people/?keywords=growth%20hacking"
],
"numberOfProfiles": 100
},
"saveResult": true
}
}
2.2. Aguardar Conclusão
// Delay: 2 minutos para processar
// HTTP Request: "Buscar Resultados"
{
"method": "GET",
"url": "https://api.phantombuster.com/api/v2/containers/fetch-result-object",
"headers": {
"X-Phantombuster-Key": "{{ $credentials.phantombuster.apiKey }}"
},
"params": {
"id": "{{ $nodes['buscar-influencers'].output.containerId }}"
}
}
2.3. Processar Resultados
// Function Node: "Normalizar Dados"
{{
(() => {
const results = $nodes['buscar-resultados'].output.resultObject || [];
return results.map(profile => ({
linkedinUrl: profile.profileUrl,
fullName: profile.fullName,
headline: profile.headline,
location: profile.location,
followersCount: profile.connectionsCount || 0,
company: profile.companyName,
jobTitle: profile.jobTitle,
industry: profile.industry
})).filter(p => p.linkedinUrl); // Apenas perfis com URL
})()
}}
Parte 3: Enriquecimento de Perfil
3.1. Extrair Dados Detalhados
// Loop/ForEach: Para cada influencer encontrado
// HTTP Request: "Scrape Profile Details"
{
"method": "POST",
"url": "https://api.phantombuster.com/api/v2/agents/launch",
"headers": {
"X-Phantombuster-Key": "{{ $credentials.phantombuster.apiKey }}"
},
"body": {
"id": "{{ $vars.linkedinProfileScraperAgentId }}",
"argument": {
"sessionCookie": "{{ $credentials.linkedin.sessionCookie }}",
"profileUrls": ["{{ $item.linkedinUrl }}"],
"includeLastPosts": true
}
}
}
3.2. Calcular Métricas de Engajamento
// Function Node: "Calcular Engagement"
{{
(() => {
const posts = $nodes['scrape-profile'].output.posts || [];
if (posts.length === 0) {
return {
postsPerWeek: 0,
avgEngagementRate: 0,
topics: []
};
}
// Posts por semana (últimos 30 dias)
const recentPosts = posts.filter(p => {
const postDate = new Date(p.date);
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
return postDate >= thirtyDaysAgo;
});
const postsPerWeek = (recentPosts.length / 30) * 7;
// Taxa de engajamento média
const totalEngagement = recentPosts.reduce((sum, post) => {
return sum + (post.likes || 0) + (post.comments || 0) + (post.shares || 0);
}, 0);
const followersCount = $item.followersCount || 1;
const avgEngagementRate = (totalEngagement / (recentPosts.length * followersCount)) * 100;
// Extrair tópicos dos posts
const allText = recentPosts.map(p => p.text || '').join(' ').toLowerCase();
const topicKeywords = ['marketing', 'automation', 'saas', 'growth', 'sales', 'ai', 'tech'];
const topics = topicKeywords.filter(keyword => allText.includes(keyword));
return {
postsPerWeek: Math.round(postsPerWeek * 10) / 10,
avgEngagementRate: Math.round(avgEngagementRate * 100) / 100,
topics,
recentPosts: recentPosts.slice(0, 5).map(p => ({
text: p.text?.substring(0, 200),
likes: p.likes,
comments: p.comments,
date: p.date
}))
};
})()
}}
3.3. Enriquecer Email (Hunter.io)
// HTTP Request: "Buscar Email"
{
"method": "GET",
"url": "https://api.hunter.io/v2/email-finder",
"params": {
"domain": "{{ $item.company ? $item.company.toLowerCase().replace(/\s/g, '') + '.com' : '' }}",
"first_name": "{{ $item.fullName?.split(' ')[0] }}",
"last_name": "{{ $item.fullName?.split(' ').slice(-1)[0] }}",
"api_key": "{{ $credentials.hunter.apiKey }}"
},
"errorHandling": "continueOnFail"
}
Parte 4: Qualificação e Scoring
4.1. Calcular Score
// Function Node: "Calcular Score de Relevância"
{{
(() => {
let relevanceScore = 0;
let qualityScore = 0;
const profile = {
...$item,
...$nodes['calc-engagement'].output
};
// RELEVANCE SCORE (0-100)
// Baseado em alinhamento com ICP
// Tópicos relevantes (0-30 pontos)
const targetTopics = ['marketing', 'automation', 'saas', 'growth'];
const matchingTopics = (profile.topics || []).filter(t => targetTopics.includes(t));
relevanceScore += Math.min(matchingTopics.length * 10, 30);
// Headline relevante (0-20 pontos)
const headline = (profile.headline || '').toLowerCase();
if (headline.includes('cmo') || headline.includes('marketing director')) {
relevanceScore += 20;
} else if (headline.includes('marketing') || headline.includes('growth')) {
relevanceScore += 15;
}
// Indústria target (0-20 pontos)
const targetIndustries = ['software', 'technology', 'saas', 'internet'];
if (targetIndustries.some(ind => (profile.industry || '').toLowerCase().includes(ind))) {
relevanceScore += 20;
}
// Localização (0-15 pontos)
const location = (profile.location || '').toLowerCase();
if (location.includes('brazil') || location.includes('brasil')) {
relevanceScore += 15;
} else if (location.includes('latin america')) {
relevanceScore += 10;
}
// Empresa conhecida (0-15 pontos)
const knownCompanies = ['google', 'microsoft', 'amazon', 'meta', 'salesforce'];
if (knownCompanies.some(comp => (profile.company || '').toLowerCase().includes(comp))) {
relevanceScore += 15;
}
// QUALITY SCORE (0-100)
// Baseado em alcance e engajamento
// Seguidores (0-40 pontos)
const followers = profile.followersCount || 0;
if (followers >= 100000) qualityScore += 40;
else if (followers >= 50000) qualityScore += 35;
else if (followers >= 10000) qualityScore += 30;
else if (followers >= 5000) qualityScore += 25;
else if (followers >= 1000) qualityScore += 15;
else qualityScore += 5;
// Engajamento (0-40 pontos)
const engagement = profile.avgEngagementRate || 0;
if (engagement >= 5) qualityScore += 40;
else if (engagement >= 3) qualityScore += 35;
else if (engagement >= 2) qualityScore += 30;
else if (engagement >= 1) qualityScore += 20;
else qualityScore += 10;
// Frequência de posts (0-20 pontos)
const postsPerWeek = profile.postsPerWeek || 0;
if (postsPerWeek >= 5) qualityScore += 20;
else if (postsPerWeek >= 3) qualityScore += 15;
else if (postsPerWeek >= 1) qualityScore += 10;
else qualityScore += 5;
// Score total (média ponderada)
const totalScore = Math.round((relevanceScore * 0.6) + (qualityScore * 0.4));
// Tier
let tier;
if (totalScore >= 80) tier = 'A';
else if (totalScore >= 60) tier = 'B';
else tier = 'C';
return {
relevanceScore,
qualityScore,
totalScore,
tier,
reasoning: {
topicsMatch: matchingTopics.length,
followers,
engagement,
postsPerWeek
}
};
})()
}}
4.2. Filtrar por Score Mínimo
// If/Else: "Score Suficiente?"
{{
$nodes['calcular-score'].output.totalScore >= 40 // Apenas B e A
}}
Parte 5: Salvar e Criar no CRM
5.1. Inserir no Banco
// Database Insert: "Salvar Influencer"
{
"table": "influencers",
"data": {
"linkedin_url": "{{ $item.linkedinUrl }}",
"full_name": "{{ $item.fullName }}",
"headline": "{{ $item.headline }}",
"location": "{{ $item.location }}",
"followers_count": "{{ $item.followersCount }}",
"posts_per_week": "{{ $nodes['calc-engagement'].output.postsPerWeek }}",
"avg_engagement_rate": "{{ $nodes['calc-engagement'].output.avgEngagementRate }}",
"relevance_score": "{{ $nodes['calcular-score'].output.relevanceScore }}",
"quality_score": "{{ $nodes['calcular-score'].output.qualityScore }}",
"total_score": "{{ $nodes['calcular-score'].output.totalScore }}",
"tier": "{{ $nodes['calcular-score'].output.tier }}",
"company": "{{ $item.company }}",
"job_title": "{{ $item.jobTitle }}",
"industry": "{{ $item.industry }}",
"topics": "{{ JSON.stringify($nodes['calc-engagement'].output.topics) }}",
"recent_posts": "{{ JSON.stringify($nodes['calc-engagement'].output.recentPosts) }}",
"email": "{{ $nodes['buscar-email']?.output.data?.email || null }}",
"status": "new"
},
"onConflict": "ignore",
"returning": ["id"]
}
5.2. Criar Contato no HubSpot
// HTTP Request: "Criar no HubSpot"
{
"method": "POST",
"url": "https://api.hubapi.com/crm/v3/objects/contacts",
"headers": {
"Authorization": "Bearer {{ $credentials.hubspot.accessToken }}",
"Content-Type": "application/json"
},
"body": {
"properties": {
"firstname": "{{ $item.fullName?.split(' ')[0] }}",
"lastname": "{{ $item.fullName?.split(' ').slice(-1)[0] }}",
"email": "{{ $nodes['buscar-email']?.output.data?.email }}",
"company": "{{ $item.company }}",
"jobtitle": "{{ $item.jobTitle }}",
"linkedin_url": "{{ $item.linkedinUrl }}",
"hs_lead_status": "{{ $nodes['calcular-score'].output.tier === 'A' ? 'OPEN' : 'NEW' }}",
"lifecyclestage": "lead",
// Custom properties
"influencer_tier": "{{ $nodes['calcular-score'].output.tier }}",
"influencer_score": "{{ $nodes['calcular-score'].output.totalScore }}",
"linkedin_followers": "{{ $item.followersCount }}",
"engagement_rate": "{{ $nodes['calc-engagement'].output.avgEngagementRate }}"
}
}
}
Parte 6: Outreach Automático
6.1. Flow de Outreach (Schedule Trigger - diário)
// Database Query: "Buscar Influencers Pendentes"
SELECT *
FROM influencers
WHERE status = 'new'
AND tier IN ('A', 'B')
AND outreach_stage = 0
ORDER BY total_score DESC
LIMIT 20; -- Limitar para não fazer spam
6.2. Personalizar Mensagem de Conexão
// Function Node: "Gerar Mensagem Personalizada"
{{
(() => {
const profile = $item;
const firstName = profile.full_name?.split(' ')[0] || 'profissional';
const topics = JSON.parse(profile.topics || '[]');
const recentPosts = JSON.parse(profile.recent_posts || '[]');
// Escolher gancho baseado no perfil
let hook = '';
if (recentPosts.length > 0) {
const latestPost = recentPosts[0];
hook = `Vi seu post sobre "${latestPost.text?.substring(0, 50)}..." e adorei a perspectiva!`;
} else if (topics.includes('marketing')) {
hook = 'Percebi que você tem grande expertise em marketing automation.';
} else if (topics.includes('saas')) {
hook = 'Vejo que você é referência no universo SaaS.';
} else {
hook = `Seu trabalho em ${profile.company || 'sua área'} chamou minha atenção.`;
}
// Templates por tier
const templates = {
A: `Olá, ${firstName}! ${hook} Gostaria de trocar ideias sobre automação e inovação. Vamos conectar?`,
B: `Oi, ${firstName}! ${hook} Seria ótimo ter você na minha rede para trocarmos experiências.`,
C: `Olá, ${firstName}! Gostaria de conectar com profissionais da área de ${profile.industry || 'tecnologia'}. Vamos?`
};
return {
connectionMessage: templates[profile.tier] || templates.C,
hook
};
})()
}}
6.3. Enviar Connection Request
// HTTP Request: "Enviar Convite no LinkedIn"
{
"method": "POST",
"url": "https://api.phantombuster.com/api/v2/agents/launch",
"headers": {
"X-Phantombuster-Key": "{{ $credentials.phantombuster.apiKey }}"
},
"body": {
"id": "{{ $vars.linkedinConnectAgentId }}",
"argument": {
"sessionCookie": "{{ $credentials.linkedin.sessionCookie }}",
"profileUrls": ["{{ $item.linkedin_url }}"],
"message": "{{ $nodes['gerar-mensagem'].output.connectionMessage }}",
"onlySecondCircle": false
}
}
}
6.4. Registrar Envio
// Database Insert: "Registrar Mensagem"
{
"table": "outreach_messages",
"data": {
"influencer_id": "{{ $item.id }}",
"sequence_stage": 0,
"message_type": "connection_request",
"content": "{{ $nodes['gerar-mensagem'].output.connectionMessage }}",
"sent_at": "{{ new Date().toISOString() }}"
}
}
// Database Update: "Atualizar Status"
{
"table": "influencers",
"data": {
"status": "contacted",
"outreach_stage": 1,
"first_contact_at": "{{ new Date().toISOString() }}",
"last_contact_at": "{{ new Date().toISOString() }}"
},
"where": {
"id": "{{ $item.id }}"
}
}
Parte 7: Sequência de Follow-up
7.1. Follow-up Automático (7 dias depois)
// Database Query: "Influencers Para Follow-up"
SELECT *
FROM influencers
WHERE status = 'contacted'
AND outreach_stage = 1
AND first_contact_at <= NOW() - INTERVAL '7 days'
AND NOT EXISTS (
SELECT 1 FROM outreach_messages
WHERE influencer_id = influencers.id
AND sequence_stage = 1
)
LIMIT 10;
7.2. Mensagem de Follow-up
// Function Node: "Mensagem Follow-up"
{{
const firstName = $item.full_name?.split(' ')[0];
return {
message: `Oi, ${firstName}! Espero que esteja bem. Gostaria de conversar sobre uma parceria que pode ser interessante para nós dois. Quando tiver um tempinho, me avise! 😊`
};
}}
7.3. Enviar Mensagem Direta
// HTTP Request: "Enviar Mensagem LinkedIn"
{
"method": "POST",
"url": "https://api.phantombuster.com/api/v2/agents/launch",
"headers": {
"X-Phantombuster-Key": "{{ $credentials.phantombuster.apiKey }}"
},
"body": {
"id": "{{ $vars.linkedinMessageAgentId }}",
"argument": {
"sessionCookie": "{{ $credentials.linkedin.sessionCookie }}",
"profileUrls": ["{{ $item.linkedin_url }}"],
"message": "{{ $nodes['mensagem-followup'].output.message }}"
}
}
}
Parte 8: Tracking de Respostas
8.1. Webhook para Respostas (Manual)
Como o LinkedIn não fornece webhooks, você pode:
- Usar PhantomBuster para scraping de mensagens recebidas
- Atualizar manualmente via interface
- Integrar com ferramentas como Lemlist
// Webhook Trigger: Resposta Recebida
// Processar e atualizar status
// Database Update: "Marcar Como Respondido"
{
"table": "influencers",
"data": {
"status": "responded",
"responded_at": "{{ new Date().toISOString() }}"
},
"where": {
"linkedin_url": "{{ $trigger.body.profile_url }}"
}
}
Teste e Métricas
-- Performance do outreach
SELECT
tier,
COUNT(*) as total,
COUNT(*) FILTER (WHERE status = 'contacted') as contacted,
COUNT(*) FILTER (WHERE status = 'responded') as responded,
COUNT(*) FILTER (WHERE status = 'partnership') as partnerships,
ROUND(
COUNT(*) FILTER (WHERE status = 'responded')::DECIMAL /
NULLIF(COUNT(*) FILTER (WHERE status = 'contacted'), 0) * 100,
2
) as response_rate
FROM influencers
GROUP BY tier
ORDER BY tier;
Próximos Passos
- Campanha Multicanal - Engaje além do LinkedIn
- Lead Scoring - Qualifique parcerias
- Content Distribution - Distribua conteúdo via influencers
Última atualização: Janeiro 2025