No enrichment tool is accurate until it passes a sample you built yourself. Every vendor page says "accurate data". None of them can show your market.
This guide gives you the test: 100 contacts, one scoring script, nine tools. The same test works for any tool you add later. It ends with a table of what each of the nine lets you try for free.
I picked the nine for one reason: each has a free tier or free credits, so you can run the test without a contract.
TL;DR
- The full test takes about 2 hours across nine tools. One tool takes about 20 minutes.
- It spends about 100 LeadOcean records. Counts, 404s and empty pages cost nothing.
- Score each tool on three numbers: hit rate, email status you can read, and bounce rate on a 20-address send.
Prerequisites
- A LeadOcean API key from app.leadocean.io. Free is 1,000 records, one-off, no card.
- The key exported as
$LEADOCEAN_API_KEY. - Free accounts at the tools you want to test, and
curl,jqand Python 3. - A sending domain you can afford to bounce on. Use a throwaway, not your main one.
export LEADOCEAN_API_KEY="paste-your-key-here"Step 1: Size the segment you care about
Test on the people you will actually buy, not a generic list. Count first. A count is free.
curl -s -G https://api.leadocean.io/v1/people/search \
-H "x-api-key: $LEADOCEAN_API_KEY" \
--data-urlencode "jobLevel=VP" \
--data-urlencode "jobFunction=Sales & Business Development" \
--data-urlencode "country=CA" \
--data-urlencode "count=true" \
--data-urlencode "limit=1" | jq '.meta | {total, totalIsExact}'The same count through the MCP tool leadocean_count_leads on 2026-10-21 returned the numbers below. That is 5,574 people with an email worth sending to, out of 18,800 matching the filters with no email condition.
Skip the filters you cannot map to another tool's input. A fair test changes one thing: the tool. Same 100 inputs, same day, same scoring script.
The free count also tells you if your segment is big enough to test at all. If it returns under a few hundred, test a broader segment first.
Step 2: Pull 100 rows as your sample
Search returns a thin row with a person_id and contact flags. Each person returned costs 1 record. Filters are arrays in a flat JSON body, and limit runs 1 to 100.
curl -s 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": ["CA"],
"limit": 100
}' > sample.jsonKeep sample.json. It is your answer key for company, title and country. Do not use it as the answer key for email: that is the thing under test.
Step 3: Strip the sample to what a real lead list gives you
In practice you hold a LinkedIn URL, a work email, or a name and a domain. Pick the one your real lists contain. LeadOcean enrich takes exactly one of linkedin_url, email, phone or person_id. It has no name plus domain lookup: search by domain first, then enrich by person_id.
curl -s 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-example", "reveal_email": true}' \
| jq '.data.contact_data | {email_status, contact_emails}'Write the 100 inputs to a CSV with one column per input type. Send the same CSV to every tool.
Step 4: Run each tool and record three things
For every tool, log whether it returned a hit, what email it returned, and what status it attached. A status you can read is worth more than a bare address.
LeadOcean attaches one of 13 email_status values. verified, catch_all_valid and catch_all are the mailable ones. A person we hold nothing for is a 404 and costs nothing.
curl -s 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 -r '.data.contact_data | [.email_status, .contact_emails[0].email] | @tsv'Step 5: Score every tool with one script
Save each tool's output as tool.csv with columns input, email, status. This script prints the hit rate and the share with a readable status.
import csv, sys
rows = list(csv.DictReader(open(sys.argv[1])))
hits = [r for r in rows if r["email"].strip()]
with_status = [r for r in hits if r["status"].strip()]
print(f"rows={len(rows)} hit_rate={len(hits)/len(rows):.0%} "
f"status_on_hits={len(with_status)/max(len(hits),1):.0%}")A high hit rate with no status is a warning. You cannot tell the good addresses from the guesses.
Step 6: Send 20 addresses per tool and count bounces
Hit rate is not accuracy. Bounce rate is closer. Take 20 returned addresses per tool, send one plain email from the throwaway domain, and count hard bounces.
Keep it to 20. This is a signal, not a benchmark, and it will not hold up as a published result. Run it again next month: the LeadOcean dataset is refreshed monthly.
LeadOcean gives no refund or credit-back for bounces. Read email_status before sending.
Step 7: Know what each of the nine lets you try for free
The free tiers below are list figures I read in September 2026. Check each page before you plan around it.
| Tool | Free way in | Source |
|---|---|---|
| LeadOcean | 1,000 records for life, no card, 5 requests a second | app.leadocean.io |
| Apollo | Free plan, 75 credits a month. An email is 1 credit, a phone number 8 | Apollo pricing, September 2026 |
| Hunter | Free plan, 50 credits a month. Nothing found costs no credit | Hunter pricing, September 2026 |
| Prospeo | Free plan, 100 credits a month. A verified email is 1 credit, a mobile 10 | Prospeo pricing, September 2026 |
| People Data Labs | Free plan, up to 100 credits a month, contact data obscured | PDL pricing, September 2026 |
| FullEnrich | 50 free credits, no card. Not found costs 0 credits | FullEnrich pricing, September 2026 |
| Clay | Free plan, 100 Data Credits a month, no phone enrichment | Clay pricing, September 2026 |
| Lusha | Free plan, 40 credits a month, 1 seat | Lusha pricing, September 2026 |
| GTM AI (ZoomInfo) | Free at signup: 1,000 data credits, no card. Search and lookup are free | GTM AI pricing, September 2026 |
Note the limits. Hunter's 50 credits and Lusha's 40 are too small for a 100-row test. Split the sample, or test 40 rows. Prospeo's pricing table shows no Public API on Free, while its help center lists limited Free API access (Prospeo plans overview, September 2026). If the API refuses your free key, run the test in its app.
Apollo is priced per seat. Clay runs waterfalls across data providers inside a table (Clay pricing, September 2026), so score the waterfall you configure, not Clay alone.
Step 8: Read the scores against what you buy
Pick on the metric that matches your job, not on the highest hit rate. A tool that returns an address for every row and labels none of them will bounce you into a spam folder.
- Cold email at volume: weight the readable status and the bounce count. Send only to addresses the tool itself marks as checked.
- Enrichment inside a CRM: weight hit rate on your real input, usually a LinkedIn URL or an email. Misses cost you a blank field.
- Phones for a dialer: test phones separately. Apollo charges 8 credits and Prospeo 10 for a mobile, so a phone test burns a free tier fast.
- An AI agent doing research: weight how the tool is reached. LeadOcean runs a hosted MCP server with 13 tools, and the count and filter tools are free.
Then compare cost per useful row, not cost per credit. A credit that returns a dead address is not cheap.
Step 9: Re-test every quarter
Data decays as people change jobs. Keep sample.json, rerun Steps 3 to 6 each quarter, and compare to last time. A tool that drops 10 points in a quarter is telling you something.
What you get
At the end you hold nine rows of three numbers. This is the shape of a LeadOcean enrich response from the API reference, with placeholder values, not a real record.
{
"data": {
"contact_data": {
"email_status": "verified",
"contact_emails": [
{ "email": "jane.doe@acme.com" }
]
}
}
}Response shape from the API reference. The free count from Step 1, run on 2026-10-21:
{
"total": 5574,
"totalIsExact": true,
"totalAll": 18800,
"distinctCompanies": 3873,
"credits": 0
}The 5,574 is the mailable audience (verified, catch_all_valid or catch_all) for VP, Sales & Business Development, Canada. It is not everyone matching those filters.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing or bad x-api-key header | Re-export $LEADOCEAN_API_KEY and check for trailing whitespace |
| 429 | More requests a second than the plan allows (5 on Free, 200 on Agency) | Honour Retry-After and slow the loop |
| 402 | The 1,000 free records are spent | Move to Solo ($97 a month). Free records are one-off and do not renew |
| 404 on enrich | We hold nothing for that person | Free. Count it as a miss in your score |
| Empty search results | A bad enum value, such as a free-text industry | Resolve values with GET /v1/enums or leadocean_list_enum_values |
| Export refused | Over 50,000 rows a request or 500,000 a day, or an export on Free | Split the request. Bulk CSV export is not on Free |
FAQ
Which tool is the most accurate?
I will not name one without your sample. Accuracy depends on your region, seniority and industry. The test above is the answer for your market.
Why not trust a vendor's accuracy percentage?
The vendor chose the sample and the definition of accurate. Your sample uses your segment, and the bounce count is yours.
How big should the sample be?
100 rows gives a rough signal. Below 50 the noise swamps the difference. Use 300 or more if two tools score close.
What does it cost to run at scale afterwards?
On paid LeadOcean plans there is a fair-use pace, not credits. Solo is $97 a month for one person and Agency is $497 a month for teams. See pricing and what enrichment really costs.
Run the accuracy test on your own segment
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →