DEV Community

Cover image for Build a LinkedIn Lead Enricher for your CRM with Node.js
Olamide Olaniyan
Olamide Olaniyan

Posted on

Build a LinkedIn Lead Enricher for your CRM with Node.js

If you've ever worked in sales or with a sales team, you know the pain of "enrichment."

It usually looks like this:

  1. Find a prospect on LinkedIn.
  2. Copy their Name. Switch tabs. Paste into CRM.
  3. Copy their Job Title. Switch tabs. Paste into CRM.
  4. Copy their Company. Switch tabs. Paste into CRM.
  5. Repeat 50 times a day.

It’s soul-crushing work. And worse, it’s prone to human error.

In this tutorial, I’m going to show you how to automate this entire process using Node.js and the SociaVault API. We’ll build a simple script that takes a LinkedIn URL, scrapes the public profile data, and formats it perfectly for your CRM.

What We're Building

We will build a command-line tool that:

  1. Accepts a LinkedIn Profile URL.
  2. Fetches the full profile data (Headline, About, Experience, Education).
  3. Returns a clean JSON object ready for your database or CRM (HubSpot, Salesforce, Pipedrive).

Prerequisites

  • Node.js installed on your machine.
  • A text editor (VS Code).
  • A SociaVault API Key (You can grab one here).

Step 1: Setup Your Project

First, let's create a new directory and initialize our project.

mkdir linkedin-enricher
cd linkedin-enricher
npm init -y
Enter fullscreen mode Exit fullscreen mode

We'll need axios to make the HTTP requests and dotenv to manage our API key securely.

npm install axios dotenv
Enter fullscreen mode Exit fullscreen mode

Create a .env file in your root directory:

SOCIAVAULT_API_KEY=your_api_key_here
Enter fullscreen mode Exit fullscreen mode

Step 2: The Enrichment Script

Create a file named enrich.js. This is where the magic happens.

We'll use the v1/scrape/linkedin/profile endpoint. It's designed specifically for this use case—it returns structured data from any public LinkedIn profile.

require('dotenv').config();
const axios = require('axios');

const API_KEY = process.env.SOCIAVAULT_API_KEY;
const BASE_URL = 'https://api.sociavault.com/v1/scrape/linkedin/profile';

async function enrichLead(linkedInUrl) {
  if (!linkedInUrl) {
    console.error('❌ Please provide a LinkedIn URL');
    return;
  }

  console.log(`🔍 Enriching profile: ${linkedInUrl}...`);

  try {
    const response = await axios.get(BASE_URL, {
      params: { url: linkedInUrl },
      headers: {
        'Authorization': `Bearer ${API_KEY}`,
        'Content-Type': 'application/json'
      }
    });

    const data = response.data.data;

    // The API returns a lot of data. Let's extract just what a CRM needs.
    const lead = {
      fullName: data.name,
      headline: data.headline,
      location: data.location,
      summary: data.about ? data.about.substring(0, 200) + '...' : '', // Truncate for CRM
      currentRole: data.position_groups?.[0]?.profile_positions?.[0]?.title || 'Unknown',
      currentCompany: data.position_groups?.[0]?.profile_positions?.[0]?.company || 'Unknown',
      profileImage: data.profile_picture_url
    };

    return lead;

  } catch (error) {
    if (error.response) {
      console.error(`❌ API Error: ${error.response.status} - ${error.response.data.error}`);
    } else {
      console.error(`❌ Error: ${error.message}`);
    }
    return null;
  }
}

// Example Usage
const targetProfile = 'https://www.linkedin.com/in/satyanadella';

enrichLead(targetProfile).then(lead => {
  if (lead) {
    console.log('\n✅ Lead Enriched Successfully:');
    console.log(JSON.stringify(lead, null, 2));

    // Here you would call your CRM API to save the lead
    // saveToHubSpot(lead);
  }
});
Enter fullscreen mode Exit fullscreen mode

Step 3: Understanding the Data

When you run this script:

node enrich.js
Enter fullscreen mode Exit fullscreen mode

You'll get a clean, structured object like this:

{
  "fullName": "Satya Nadella",
  "headline": "Chairman and CEO at Microsoft",
  "location": "Redmond, Washington, United States",
  "summary": "Satya Nadella is Chairman and CEO of Microsoft. Before being named CEO in February 2014, Nadella held leadership roles in both enterprise and consumer businesses across the company...",
  "currentRole": "Chairman and CEO",
  "currentCompany": "Microsoft",
  "profileImage": "https://media.licdn.com/dms/image/..."
}
Enter fullscreen mode Exit fullscreen mode

Why this is better than scraping it yourself

You might be tempted to write your own Puppeteer script to do this. I've been there. Here is why that's a bad idea for production:

  1. Login Walls: LinkedIn is aggressive about blocking scrapers. You need to manage cookies, sessions, and 2FA.
  2. DOM Changes: LinkedIn changes their HTML class names frequently. Your script will break next week.
  3. Rate Limits: If you scrape too fast from one IP, you'll get banned.

Using an API like SociaVault abstracts all that pain away. You just make a GET request, and you get JSON back.

Step 4: Scaling It Up (Batch Processing)

In a real-world scenario, you probably have a CSV of 100 leads. Here is how you could modify the script to handle a list.

const leads = [
  'https://www.linkedin.com/in/satyanadella',
  'https://www.linkedin.com/in/williamhgates',
  // ... more urls
];

async function processBatch(urls) {
  console.log(`🚀 Starting batch enrichment for ${urls.length} leads...`);

  const results = [];

  for (const url of urls) {
    const lead = await enrichLead(url);
    if (lead) results.push(lead);

    // Be nice to the API (and your rate limits)
    await new Promise(resolve => setTimeout(resolve, 1000));
  }

  console.log(`\n✨ Batch complete! Enriched ${results.length} leads.`);
  // saveToCsv(results);
}

processBatch(leads);
Enter fullscreen mode Exit fullscreen mode

Conclusion

Building internal tools doesn't have to be complicated. With a few lines of Node.js, you can turn a manual, 2-hour daily task into a script that runs in 30 seconds while you grab coffee.

If you want to try this out, grab a free API key from SociaVault and start enriching.

Happy coding!

Top comments (0)