Build a pipeline that scrapes LinkedIn profiles with Bright Data and delivers CRM-ready contact records to a Next.js 14 webhook handler deployed on Vercel.
Use this file to discover all available pages before exploring further.
You want to enrich inbound leads automatically. A signup form gives you a LinkedIn URL, and a minute later a contact record with job title, company, location and follower count lands in your CRM. No manual copy-paste, no Zapier-style glue code.In this tutorial we’ll build that pipeline end-to-end. You’ll deploy a tiny Next.js webhook handler to Vercel, trigger the Bright Data LinkedIn Scraper API against a handful of profile URLs and watch mapped contact records appear in your Vercel logs within a minute.We stop at the mapped object. Sending it to a specific CRM is a one-line fetch call we’ll sketch out at the end.
Accepts a POST from Bright Data containing a JSON array of scraped LinkedIn profiles
Maps each profile into a normalized CRM-shaped contact record
Logs the mapped records so you can inspect them in the Vercel dashboard
You’ll then trigger a scrape from your terminal pointed at your deployed Vercel URL, and see two profiles get mapped and logged end-to-end.Estimated time: 25 minutes.
Create the file app/api/webhook/linkedin/route.ts:
app/api/webhook/linkedin/route.ts
export async function POST(request: Request) { const profiles = await request.json(); console.log(`Received ${profiles.length} profiles from Bright Data`); for (const profile of profiles) { console.log(`- ${profile.name} (${profile.position})`); } return Response.json({ received: profiles.length });}
That’s the whole receiver. Next.js App Router treats any route.ts file as an API endpoint, so this file alone gives you a working POST /api/webhook/linkedin route once deployed.
Open your project in the Vercel dashboard and keep the Logs tab visible. That’s where your console.log output will appear when Bright Data POSTs to the endpoint.
Replace YOUR_API_KEY with your Bright Data API key and linkedin-to-crm-<hash> with your actual Vercel URL.You should see a response like this immediately:
{"snapshot_id":"sd_mntfn0zq7xj0zeay"}
The scrape runs asynchronously. You don’t need to do anything with the snapshot_id. Bright Data POSTs the results to your Vercel endpoint when the job finishes. For two profiles, that usually takes 30 to 60 seconds.Switch to the Vercel Logs tab. Within a minute you should see something like:
Received 2 profiles from Bright Data- Satya Nadella (Chairman and CEO at Microsoft)- Jeff Weiner (Executive Chairman at LinkedIn)
Notice that both profiles arrive in a single POST. Bright Data delivers the whole snapshot in one request, not one profile at a time.
Right now the handler just logs names and positions. Real CRMs expect contact records with specific field names: full_name, job_title, company, and so on. Let’s normalize the Bright Data payload into that shape.Replace app/api/webhook/linkedin/route.ts with:
Re-run the same curl command from Part 4. This time your Vercel logs should show two complete mapped contacts:
Received 2 profiles from Bright Data{ "full_name": "Satya Nadella", "job_title": "Chairman and CEO at Microsoft", "company": "Microsoft", "country": "US", "city": "Redmond", "linkedin_url": "https://www.linkedin.com/in/satyanadella", "follower_count": 10842560}{ "full_name": "Jeff Weiner", "job_title": "Executive Chairman at LinkedIn", "company": "Next Chapter", "country": "US", "city": "San Francisco Bay Area", "linkedin_url": "https://www.linkedin.com/in/jeffweiner08", "follower_count": 1200000}
Each object in that log is a complete CRM-ready contact. Sending it to your CRM is a single fetch call. The commented-out block in the handler sketches the HubSpot version. Swap the URL and header for Salesforce, Pipedrive or whatever you use.
Right now anyone who guesses your Vercel URL could POST fake profile data to it. Before you pipe live data into a real CRM, lock down the endpoint.Bright Data’s trigger call accepts a webhook_header_Authorization query parameter, which gets forwarded as the Authorization header on the webhook POST:
You’ve built an end-to-end pipeline that scrapes LinkedIn profiles and delivers CRM-ready contact records to your own server:
A Next.js API route deployed on Vercel that receives Bright Data webhooks
A mapper function that normalizes Bright Data’s profile schema into a CRM-shaped contact
A trigger call that fires the scrape asynchronously and tells Bright Data exactly where to send the results
The final hop, POSTing each mapped contact to HubSpot, Salesforce or your own CRM, is a single fetch call that the commented-out block in route.ts sketches.