Pre-Black Friday: 20% off, for as long as you stayEARLYBFon Solo and AgencyEnds Nov 28Start free

How-to guide

How to Get Warm Leads from LinkedIn Posts (Step-by-Step)

List the people who engage with your posts, enrich their profile URLs, and keep the ones who match your buyer.

Get your free API key →Free to start. No credit card. 1,000 records to spend whenever you like.

TL;DR

  • A warm lead from a post is someone who engaged with it more than once and fits your buyer. You supply the engagement. LeadOcean supplies title, company and contact data.
  • It takes about 30 minutes. It spends up to 55 of your 1,000 free records, and profiles we hold nothing for cost nothing.
  • You start from profile URLs you collected yourself. Nothing here scrapes LinkedIn.

Prerequisites

  • A LinkedIn account with posts of your own, and a list of the people who reacted or commented on them. Copy names and profile URLs by hand, or from your own notes.
  • A LeadOcean API key from app.leadocean.io, as $LEADOCEAN_API_KEY. The free plan has no card and 1,000 records, one-off. It allows 5 requests a second.
  • curl and jq, plus Miller (mlr) for Step 6, or a spreadsheet.

Step 1: Write down who engaged, and how often

Warm means repeat engagement, so count it. One like is noise. Three comments across three posts is a signal.

Make engagers.csv with a header row and one line per person. Keep the profile URL, a count of engagements, and what they did.

csv
linkedin_url,engagements,note
https://www.linkedin.com/in/jane-doe-acme,4,commented on pricing post
https://www.linkedin.com/in/john-roe-example,1,liked

Those two rows use placeholder people. Drop everyone with one passive like for now. A list of 40 repeat engagers beats 400 lurkers.

Step 2: Size your buyer before you spend a record

Decide who counts as a buyer, then check how many exist. The count is free, however often you run it. It also tells you how thin your engager list is next to the market.

Pick one definition and keep it for Step 6. This example is a sales leader in the UK.

bash
curl -s "https://api.leadocean.io/v1/people/search?count=true&limit=1" \
  -X POST -H "x-api-key: $LEADOCEAN_API_KEY" -H "Content-Type: application/json" \
  -d '{"jobLevel":["VP","C-Team"],"jobFunction":["Sales & Business Development"],"country":["GB"]}' \
  | jq '.meta | {total, totalIsExact, countOnly}'

count=true goes in the query string, not the JSON body, which rejects unknown fields. The data array comes back empty, so nothing is billed. Enum values are exact strings. Resolve them with GET /v1/enums before you guess.

Step 3: Decide what makes an engager warm

Write the rule down before you enrich, or every name will look like a lead. Use three tiers and keep them in the note column.

text
hot   comment that asks a question or names a problem you solve
warm  two or more engagements across different posts
cool  a single reaction (leave out of this run)

Spend your records on hot and warm only. A comment is a stronger signal than a reaction, because the person typed something. Quote it back when you write to them in Step 7.

Step 4: Test the enrich call on five profiles

Enrich takes one identifier per call. For a LinkedIn profile that is linkedin_url. A person we hold nothing for is a 404 and costs nothing.

bash
echo "linkedin_url,engagements,name,job_title,company,domain,employees" > enriched.csv
tail -n +2 engagers.csv | head -5 | while IFS=, read -r url n note; do
  curl -s -X POST https://api.leadocean.io/v1/people/enrich \
    -H "x-api-key: $LEADOCEAN_API_KEY" -H "Content-Type: application/json" \
    -d "{\"linkedin_url\":\"$url\"}" |
  jq -r --arg u "$url" --arg n "$n" '
    select(.data != null) | .data as $d | $d.contact_data.contact_current_experiences[0] as $e
    | [$u, $n, $d.profile_data.profile_full_name, $e.job_title, $e.company_name,
       $e.company_domain, $e.company_employees.number_of_employees] | @csv' >> enriched.csv
  sleep 0.3
done

The sleep keeps you under the Free limit of 5 requests a second. A note containing a comma breaks the split, so keep notes comma-free. Open enriched.csv. If the titles match the people you know, run the rest.

Step 5: Run the rest of the list

Remove head -5, use sed -n '6,41p' instead, and delete the echo line so the header is not written twice. Leave reveal_email off: you do not need an address until you know who is a buyer.

Cap yourself at 40 repeat engagers. If a call returns 404, that person is not in the database, and nothing was spent. Count the rows in enriched.csv to see how many records you used.

Step 6: Keep the engagers who match your buyer

Filter against the definition from Step 2, and make every drop explain itself.

bash
mlr --icsv --ojson filter '$employees >= 51 && $employees <= 500' then sort -nr engagements enriched.csv \
  | jq -r '.[] | select(.job_title | test("VP|Head|Director|Founder|Chief"; "i"))
  | [.name, .job_title, .company, .engagements] | @csv'

No Miller? Paste enriched.csv into a spreadsheet and filter the same two columns. Expect a short list. Most engagers are peers, vendors and students, and that is normal.

Step 7: Reveal the contact for the keepers only

For each keeper, call enrich again with reveal_email=true. The enrich docs bill one record per call, and reveal_email itself adds no charge. So this second call is one more record per keeper: keep it to 15 keepers. To skip it, add "reveal_email":true to the Step 5 body instead.

bash
curl -s -X POST "https://api.leadocean.io/v1/people/enrich" \
  -H "x-api-key: $LEADOCEAN_API_KEY" -H "Content-Type: application/json" \
  -d '{"linkedin_url":"https://www.linkedin.com/in/jane-doe-acme","reveal_email":true}' \
  | jq '.data.contact_data | {email_status, emails: [.contact_emails[]? | {email, status}]}'

Read email_status before you send. Send only verified or catch_all_valid addresses at first, and hold back catch_all until you have checked your bounce rate.

Open a message with their words, not yours. A first line such as "You asked how we price per seat on the Tuesday post" works. "Saw you engaged with my content" does not. Keep it to three sentences and one question.

Bounced emails are not refunded. Then open the person's post comments and reply to what they actually said. A message that cites their comment is the only reason this list is warm.

What you get

The run ends with a short list: name, title, company and engagement count. This is the shape, with placeholder values.

csv
name,job_title,company,engagements
Jane Doe,VP Sales,Acme,4

The enrich call returns the response shape from the API reference, shown here with placeholder values.

json
{
  "success": true,
  "data": {
    "profile_data": { "profile_full_name": "Jane Doe" },
    "contact_data": {
      "has_email": true,
      "email_status": "verified",
      "contact_current_experiences": [{
        "job_title": "VP Sales",
        "company_name": "Acme",
        "company_domain": "acme.com"
      }]
    }
  }
}

The Step 2 audience was sized with leadocean_count_leads on 21 October 2026. Filters: VP or C-Team, Sales & Business Development, country GB. It matched 10,506 people with a mailable email (verified, catch_all_valid or catch_all) and 55,010 with no email condition, across 5,563 companies. Your engager list is a small slice of that market.

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-keyCopy the key from app.leadocean.io and check $LEADOCEAN_API_KEY is exported
429Above the plan's rate limit (5 a second on Free, 200 on Agency)Add sleep 0.3 between calls, or honour the Retry-After header
402Records are spentCheck GET /v1/usage. Free is 1,000 records for life. See pricing
404 on enrichWe hold nothing for that profileNothing was billed. Try the person's work email instead
Empty search resultsA filter value is not an exact enum stringLook it up with GET /v1/enums, for example Sales & Business Development
Export refusedOver 50,000 rows a request or 500,000 a dayNarrow the filters or split the export. Bulk CSV export is not on Free

FAQ

Is this scraping LinkedIn?

No. You collect the engagers from your own posts, and LeadOcean looks up the profile URLs you send. LeadOcean does not read LinkedIn on your behalf.

How many records does it cost?

One per profile we find. A profile we hold nothing for is a 404 and is free. The test run is at most 5 records, a full list of 40 is at most 40, and revealing contacts for 15 keepers adds up to 15 more.

Why enrich by linkedin_url and not by name?

Enrich takes exactly one of linkedin_url, email, phone or person_id. There is no name plus company lookup. Search by domain first if you only have a name.

Can I find more people like my best engager?

Yes. Take their job level, function and company size, and run the free count from Step 2. Searching then spends one record per person returned. See the best LinkedIn lead generation tools for the wider field.

What about Slack or cold-call lists?

The same method works on a Slack community: see warm Slack leads with Claude Code. For calls, read how to warm up leads before cold calling.

Turn your post engagers into a buyer list

Free to start. No credit card. 1,000 records to spend whenever you like.

Get your free API key →