When a lead submits their email through your form, you need more than just an email address. You need their LinkedIn profile, job title, company details, and work history to qualify and personalize your outreach. Here's how to architect an n8n workflow that enriches inbound leads automatically using Dropcontact's LinkedIn lookup API and Apify's profile scraper.
Architecture Overview
The enrichment pipeline follows this data flow:
Form Submission (email)
↓
Dropcontact API (email → LinkedIn URL)
↓
Conditional Branch (LinkedIn found?)
↓
Apify Scraper (LinkedIn URL → profile data)
↓
Google Sheets / CRM (structured lead data)
This architecture separates the LinkedIn URL discovery (Dropcontact) from the profile scraping (Apify) because they solve different problems. Dropcontact specializes in email-to-LinkedIn matching across its database, while Apify handles the heavy lifting of extracting structured data from LinkedIn profiles.
The conditional branch handles cases where Dropcontact can't find a LinkedIn profile—typically personal email addresses or new professionals without established online presence. Rather than breaking the workflow, these leads get captured with minimal data for manual follow-up.
API Integration: Dropcontact LinkedIn Lookup
Authentication: Dropcontact uses API key authentication. Generate your key from the Dropcontact dashboard and configure it as a credential in n8n.
Endpoint: POST https://api.dropcontact.io/enrich
Request Structure:
{
"data": [
{
"email": "john.doe@company.com"
}
]
}
Response Structure:
{
"success": true,
"data": [
{
"email": "john.doe@company.com",
"linkedin": "https://www.linkedin.com/in/johndoe",
"first_name": "John",
"last_name": "Doe"
}
]
}
Key Configuration in n8n:
- Resource:
Contact - Operation:
Enrich - Email field:
{{ $json.email }} - Simplify Output:
OFF(preserve all fields)
What to expect: Dropcontact returns the linkedin field when a match is found. Match rates vary: B2B company emails typically see 60-80% match rates, while personal emails (Gmail, Yahoo) may only match 20-30%.
API Integration: Apify LinkedIn Profile Scraper
Authentication: Apify uses token-based authentication. Get your API token from Apify Account Settings and add it as a credential in n8n.
Actor: The workflow uses Apify's "LinkedIn Profile Scraper" Actor (ID: apify/linkedin-profile-scraper). This Actor handles authentication, rate limiting, and anti-bot detection automatically.
Request Format (via n8n Apify node):
{
"profileUrls": [
"{{ $json.linkedin }}"
],
"proxyConfiguration": {
"useApifyProxy": true
}
}
Response Structure:
{
"linkedinUrl": "https://www.linkedin.com/in/johndoe",
"firstName": "John",
"lastName": "Doe",
"fullName": "John Doe",
"headline": "Senior Product Manager at Tech Corp",
"connections": 1247,
"location": "San Francisco Bay Area",
"company": "Tech Corp",
"positions": [...],
"schools": [...],
"skills": ["Product Management", "Agile", "Strategy"]
}
Key Configuration in n8n:
- Resource:
Actor - Operation:
Run an Actor and Get Dataset - Actor: Search for "LinkedIn Profile Scraper" or use recently used
- Memory:
1024 MB(sufficient for single profile scraping) - Input JSON: Pass the LinkedIn URL from Dropcontact's response
Rate Limits: Apify Actors run with their own rate limiting logic. The LinkedIn scraper typically handles 50-100 profiles per hour safely. For higher volume, configure proxy rotation in the Actor settings.
Implementation Gotchas
Missing LinkedIn Profiles: Not every email has a discoverable LinkedIn profile. The workflow includes a conditional branch (IF node) that checks if Dropcontact returned a linkedin field:
// Condition in IF node
{{ $json.linkedin }} exists
When false, the workflow captures just the email rather than attempting to scrape a non-existent profile.
Apify Actor Failures: LinkedIn's anti-scraping measures occasionally cause Actor runs to fail. Common failure modes:
-
Session expired: LinkedIn detected automated behavior -
Profile not found: URL is valid but profile is private or deleted -
Timeout: Profile loaded too slowly
Handle these by checking Apify's execution status before processing results. The n8n node returns an executionStatus field—only proceed if it's SUCCEEDED.
Data Structure Variations: Apify's output format can vary based on profile completeness. Always validate field existence before mapping:
// Safe field access in Set node
{{ $json.headline || 'No headline available' }}
{{ $json.connections || 0 }}
Google Sheets Column Mapping: The workflow uses automatic column mapping, which requires your sheet headers to exactly match field names (email, linkedinUrl, firstName, lastName, fullName, headline, connections). Create these columns before running the workflow.
Cost Optimization: Both Dropcontact and Apify charge per API call. To minimize costs:
- Deduplicate leads before enrichment (check if email already exists in your database)
- Cache Dropcontact results—LinkedIn URLs rarely change
- Batch Apify requests when possible (modify the workflow to collect multiple URLs, then pass as array)
Prerequisites
Before implementing this workflow:
Required Accounts:
- n8n (self-hosted or cloud)
- Dropcontact (free tier: 50 credits/month, paid plans from $29/month)
- Apify (free tier: $5 monthly credit, paid plans from $49/month)
- Google account (for Sheets integration)
API Credentials:
- Dropcontact API key (generate here)
- Apify API token (generate here)
- Google Sheets OAuth2 credentials (configured via n8n's Google Sheets credential flow)
Estimated Costs: For 200 leads/month:
- Dropcontact: ~$29/month (200 enrichments)
- Apify: ~$10/month (200 profile scrapes at $0.05 each)
Get the Complete n8n Workflow Configuration
This tutorial covers the API integration architecture and key implementation patterns. For the complete n8n workflow JSON with all node configurations, error handling logic, and a video walkthrough showing the workflow in action, check out the full implementation guide.
Top comments (0)