Your cold email response rate is replies divided by emails delivered, and the fastest way to raise it is to fix the list before you touch the copy. This guide defines the rate, sizes a tight segment for free, and pulls only addresses worth sending to.
TL;DR
- Count replies against delivered emails, not sent emails, and track bounces as a separate number.
- Narrow the list by title, function, size and country, and send only to
verifiedaddresses first. - It takes about 20 minutes and spends 25 LeadOcean records for the test page (the Step 4 cohorts add up to 200). Sizing queries cost nothing.
Prerequisites
- A LeadOcean API key in
$LEADOCEAN_API_KEY. The Free plan has 1,000 records for life, no card, 5 requests a second. curlandjq.- A sending tool that reports delivered, bounced and replied per email. Any sequencer that exports these counts works.
Step 1: Define the rate before you measure it
Use one formula and keep it fixed across campaigns, so numbers stay comparable.
delivered = sent - bounced
response rate = replies / delivered
positive rate = positive replies / delivered
bounce rate = bounced / sentSent is the wrong denominator. A list with 8% bounces looks like it has a worse response rate than it does, and the real problem is the list, not the copy. Log bounces and replies separately, and tag each reply as positive, negative or out of office.
Auto-replies and out-of-office messages are not responses. Strip them before you divide.
Step 2: Size a tight segment for free
A narrow list gets replies because the message fits the reader. Size candidates with a count call. It spends no records.
curl -s -X POST "https://api.leadocean.io/v1/people/search?count=true&limit=1" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jobLevel": ["VP"],
"jobFunction": ["Sales & Business Development"],
"country": ["US"],
"employeeRange": ["51-200"],
"emailStatus": ["verified"]
}' | jq '.meta'count=true goes in the query string, not the JSON body, which rejects unknown fields. The body is flat JSON and every filter is an array of strings. meta.total is capped at 100,000.
In an AI client, the same check is the leadocean_count_leads MCP tool.
Step 3: Pick the email status you will send to
Deliverability decides how many emails reach a person at all. LeadOcean returns an email_status per address: verified, catch_all_valid, catch_all, risky, unknown, untested, invalid, role, disposable, spam_trap, abuse, derived or none.
Start with verified. Add catch_all_valid and catch_all once the first campaign shows a bounce rate you accept. There is no refund for bounced emails, so read the status before you send.
curl -s -X POST "https://api.leadocean.io/v1/people/search" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jobLevel": ["VP"],
"jobFunction": ["Sales & Business Development"],
"country": ["US"],
"employeeRange": ["51-200"],
"emailStatus": ["verified"],
"limit": 25
}' | jq '{next: .meta.nextCursor, rows: (.data | length)}'This spends 25 records. Page further with the cursor from the response. One search pages to 10,000 rows, then meta.depthCapped is true: narrow the filters instead.
Before you send, check the three things that move the rate more than copy does.
- Fit. Does the title own the problem you describe? A VP of Sales reads a pipeline email differently from a VP of Finance. Filter by
jobFunction, not only byjobLevel. - Size. A message written for a 60-person company misses at 5,000 people. Use
employeeRangeto keep one message per size band. - Freshness. Titles change. The dataset is refreshed monthly and each record carries its own
fetched_atdate, so check it before a large send.
Step 4: Split into two cohorts and test one variable
Split the segment by one filter, send the same message, and compare reply rates. Seniority is a good first split because it changes who reads the email.
for level in VP Director; do # cohort A: VPs, cohort B: Directors; 100 each, 200 records
curl -s -X POST "https://api.leadocean.io/v1/people/search" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"jobLevel\":[\"$level\"],\"jobFunction\":[\"Sales & Business Development\"],\"country\":[\"US\"],\"emailStatus\":[\"verified\"],\"limit\":100}" \
> "cohort_$level.json"
doneChange nothing else: same copy, same send window, same sender. With a few hundred emails per cohort, treat small gaps as noise. Do not call a winner on a difference of a couple of replies.
For a large send, export the segment from the Exports page in the app. It has a filter builder, a column picker, a price preview and a CSV download. You can also call POST /v1/exports, up to 50,000 rows a request and 500,000 a day. Bulk CSV export is not on Free.
Step 5: Log results and read them
Keep one row per cohort. Compare in this order: bounce rate first, then response rate, then positive rate.
cohort,sent,bounced,delivered,replies,positive,response_rate,positive_rate
vp_us_51_200,200,6,194,11,4,5.7%,2.1%The row above is a layout example with placeholder numbers, not a benchmark. If bounce rate is above your tolerance, fix the list. If bounces are low and replies are low, fix the offer or the first line.
Step 6: Fix the weakest number
Read the three numbers in order, and change one thing per round.
- Bounce rate high. Tighten
emailStatustoverified, and droproleandriskyaddresses. Re-run the count to see the new list size. - Bounce low, response low. The list is reachable but the message misses. Narrow the segment further (add
countryor a smalleremployeeRange) and rewrite the first line for that one group. - Response fine, positive low. You reach people who are not buyers. Move the title filter toward the person who owns the budget, for example from
ManagertoDirector.
Repeat on the next 100 to 200 people from the same cursor. Stop when two rounds in a row show no gain. Keep the cohort table, because it is your own benchmark.
What you get
A free count on 2026-10-21 for VPs in Sales & Business Development, US, 51-200 employees, from the leadocean_count_leads MCP tool:
| Filter set | People | Distinct companies |
|---|---|---|
Default mailable (verified, catch_all_valid, catch_all) | 18,567 | 12,192 |
emailStatus: verified only | 4,552 | 3,463 |
No email condition (totalAll) | 60,456 | not returned |
Tightening to verified cuts the list by about three quarters. That is the trade: a smaller list with fewer bounces.
Response shape from the API reference, placeholder values (/v1/people/search returns data and meta):
{
"success": true,
"data": [
{
"profile_data": {
"profile_full_name": "Jane Doe",
"profile_headline": "VP Sales at Acme"
},
"contact_data": {
"has_email": true,
"email_status": "verified",
"email_type": "work",
"contact_current_experiences": [
{ "job_title": "VP Sales", "company_name": "Acme", "company_domain": "acme.com" }
]
},
"meta": { "source_ids": { "person_id": "1234567" }, "fetched_at": "2026-10-01" }
}
],
"meta": { "count": 1, "limit": 25, "credits": 1, "nextCursor": "<cursor>" }
}Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key | Check $LEADOCEAN_API_KEY and the header name. |
| 429 | Above the plan's rate limit (5 a second on Free, 200 on Agency) | Honor Retry-After, or slow the loop. |
| 402 | The plan is out of records | Free has 1,000 for life. Upgrade or narrow the list. See pricing. |
Empty data | A filter value is not an exact string | Check leadocean_list_enum_values. jobLevel is VP, not vp. |
| 400 on a count | count=true sent in the JSON body | Move it to the query string. |
| Export refused | Over 50,000 rows a request or 500,000 a day | Split the export by filter. |
FAQ
What is a good cold email response rate?
It depends on your list, your offer and who you target, so your own history is the benchmark. Track your rate per cohort and improve against it. For outside figures, see cold email statistics.
Should I count open rate?
No. Opens are unreliable because some mail clients preload images. Count replies and positive replies against delivered emails.
Does a verified list raise the response rate?
It raises delivered volume, which protects your sender reputation and gives more people the chance to reply. Whether they do depends on the message.
How many records does a test cost?
Counts are free. Pulling one page of 25 people costs 25 records. The Free plan covers 1,000. Solo at $97 a month adds bulk export, and Agency at $497 a month suits teams that run many segments. See pricing.
How big should a test cohort be?
Big enough that one reply does not swing the rate. Start with 100 to 200 delivered emails per cohort, and treat gaps of a few replies as noise. Rerun the winner on a fresh slice before you scale it.
Where does this fit in a wider outbound process?
See B2B cold emailing for the process and cold email marketing tools for sending tools. More guides are on the blog.
Build a list worth replying to. Size it free, then pull it.
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →