A tool helps SDRs book meetings only if its contacts reach inboxes and phones that pick up. Vendor rankings cannot tell you that. A split test on your own list can.
We did not run an 11-tool test, and we will not invent one. This guide gives you the recipe to run it yourself in one afternoon of setup.
TL;DR
- Take one list of 200 target accounts, enrich the same 200 contacts with each tool, and send the same sequence to every arm.
- Setup takes about 2 hours. The sending window takes 3 weeks. The LeadOcean arm spends about 400 records; sizing is free.
- Judge on meetings booked per 100 contacts, not on fill rate. Fill rate flatters tools that return unverified addresses.
Prerequisites
- A LeadOcean API key from the free plan (1,000 records for life, no card), exported as
$LEADOCEAN_API_KEY. - Accounts on the other tools you want to compare. Use their free tiers or trials where they exist.
- A sequencer that can tag contacts by arm and report replies and meetings per tag.
curlandjq.- Two SDRs or more, so rep skill does not decide the result.
Step 1: Define the one metric and the list
Pick meetings booked per 100 contacts contacted. Everything else (fill rate, cost per email) is a diagnostic, not the goal.
Write the rules down before any data arrives. Same titles, same sequence, same send days, same reps per arm. Change one thing: the data source.
Size the audience with the free MCP tool leadocean_count_leads. On 2026-10-21 this call returned the figures below.
{
"jobFunction": ["Sales & Business Development"],
"jobLevel": ["Director", "VP"],
"country": ["US"],
"employeeRange": ["51-200"],
"facets": false
}total: 55,020 (verified, catch_all_valid or catch_all emails, the tool's default)
totalAll: 180,244 (same filters, no email condition)
distinctCompanies: 28,098Counting is free, so size as often as you like. Note the label: 55,020 is the mailable count under the default email filter, not everyone matching.
Step 2: Pull the same 200 contacts from one search
Search once, then use those same people as the input to every other tool. That removes list quality as a variable. Filters are arrays, the body is flat JSON, limit runs 1 to 100.
curl -s -X POST https://api.leadocean.io/v1/people/search \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jobFunction": ["Sales & Business Development"],
"jobLevel": ["Director", "VP"],
"country": ["US"],
"employeeRange": ["51-200"],
"limit": 100
}' | tee page1.json | jq '.meta'Take meta.nextCursor from the output and request page 2 with "cursor" set to it. Two pages of 100 is 200 records.
Export the domain and name of each person to a CSV. Give that CSV to every other tool in the test.
Step 3: Enrich each contact in the LeadOcean arm
Enrich takes exactly one of linkedin_url, email, phone or person_id. Use the person_id from step 2. Set reveal_email to get the address.
curl -s -X POST https://api.leadocean.io/v1/people/enrich \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"person_id": "PERSON_ID_FROM_STEP_2", "reveal_email": true}' \
| jq '{status: .data.contact_data.email_status, phones: .data.contact_data.contact_phones}'A person we hold nothing for returns 404 and costs nothing. With reveal_email set, the phones we hold come back in contact_phones[] on the same call. GET /v2/people/phone also returns numbers, but it charges one record per call, including a call that finds nothing.
Step 4: Score the data before you send
Send only to addresses the vendor marks safe. For LeadOcean that means verified, catch_all_valid or catch_all. Drop invalid, spam_trap, abuse and disposable. Treat risky, role and derived with care.
Apply the same rule to each competitor's status field. If a tool has no status field, send to nothing from it that you have not verified yourself, and write down that you did that.
jq -r '.data[] | [.meta.source_ids.person_id, .contact_data.email_status] | @csv' page1.json \
| awk -F, '{print $2}' | sort | uniq -c | sort -rnKeep this table per arm: contacts returned, contacts safe to send, bounces after sending. Bounces are not refunded by LeadOcean, so read the status before you send.
Step 5: Send the same sequence and tag every arm
Load each arm into your sequencer with its own tag. Use the same copy, the same step delays and the same two reps rotated across arms.
Run for three weeks. Shorter windows give you replies, not meetings, and replies mislead.
arm,contacts,sent,bounced,replies,positive_replies,meetings
leadocean,200,___,___,___,___,___
tool_b,200,___,___,___,___,___
tool_c,200,___,___,___,___,___Step 6: Read the result
Divide meetings by contacts for each arm. A gap of one or two meetings on 200 contacts is noise. Do not crown a winner on that.
Rank in this order: meetings per 100, then bounce rate, then cost per meeting. Cost per meeting is the tool's monthly list price (billed monthly first, billed-yearly after it) divided by meetings, using the plan you would actually buy. Take each price from the vendor's own pricing page and note the month you checked.
If two tools tie on meetings, pick the one with the lower bounce rate. A bounce rate above a few percent hurts the sending domain for every later campaign.
What you get
A short table per arm and a recommendation you can defend. For the LeadOcean arm, an enrich response has this shape. This is the response shape from the API reference, with placeholder values.
{
"success": true,
"data": {
"profile_data": { "profile_full_name": "Jane Doe" },
"contact_data": {
"email_status": "verified",
"contact_emails": [
{ "email": "jane.doe@acme.com", "type": "work", "status": "verified" }
],
"contact_phones": [{ "phone": "+1 415 555 0133", "type": "mobile" }],
"contact_current_experiences": [
{ "job_title": "VP Sales", "company_name": "Acme", "company_domain": "acme.com" }
]
},
"resume_data": { "experiences": [], "educations": [] },
"meta": { "source_ids": { "person_id": "1234567890" }, "fetched_at": "2026-10-01" }
}
}Since October 2026 the enrich response also carries resume_data (past roles, education, certifications), which helps an SDR write a first line that is about the person.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or wrong x-api-key header | Re-export $LEADOCEAN_API_KEY and check you send it as x-api-key. |
| 429 | Above the plan's rate limit (5 requests a second on Free, 200 on Agency) | Honour the Retry-After header and loop with a short sleep. |
| 402 | The 1,000 free records are spent | Check GET /v1/account, then move to a paid plan. See /pricing. |
| Empty results | A filter value is not an exact enum string, such as vp instead of VP for jobLevel | Run leadocean_list_enum_values or GET /v1/enums and copy the exact string. |
| 404 on enrich | We hold nothing for that person | Free, no record spent. Skip the contact and log it as a miss. |
| Export refused above the ceiling | More than 50,000 rows in a request or 500,000 in a day | Split the export by filter. Bulk CSV is not on Free. |
FAQ
Why not just compare fill rates?
Fill rate counts addresses returned, not addresses that work. A tool can fill most rows and still bounce hard. Meetings per 100 contacts is the number your VP of Sales cares about.
How many contacts do I need per arm?
200 is enough to catch a big gap and too few to catch a small one. If your tools are close, run 500 per arm or accept that they tie.
Can I run this on the free plan?
Yes for the LeadOcean arm. The free plan gives 1,000 records for life, so 400 for this test leaves 600. Bulk CSV export is not on Free, so use the search and enrich calls above.
Which tool wins?
We will not guess. On your titles, your regions and your copy, one tool will win and it may not be ours. That is why you run the test.
Related reading
- Hub: Best AI outbound tools that actually book meetings
- Which enrichment tools actually work with Zendesk
- How to survey your own reps on enrichment tools
- LeadOcean pricing
Run your own enrichment bake-off with a free API key
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →