The logic before the code
Three calls do the job. intersect takes two to ten domains and returns who links to several of them. refdomains on your own site gives the set to subtract. bulk_dr then scores whatever remains.
Cost per run is tiny. Two credits for the intersect, two for your own list, one for scoring up to 2,000 domains. Five credits is $0.0005.
Order matters. Subtract before you score.
People often score everything first and filter later, which wastes nothing in money but a lot in time when the CSV has fifty thousand rows. Cut the list down by overlap count first, then ask for DR on the survivors, and keep the whole thing in a plain dict so a second run can reuse yesterday's result.
prospects.py
Domains in RIVALS are placeholders. Field names are read with .get, so check one raw row from your own run before you rely on a column.
python
import csv, json, os, urllib.request as u, urllib.parse as p
KEY = os.environ['LZ_KEY']
ME = 'mysite.example'
RIVALS = ['rival-a.example', 'rival-b.example', 'rival-c.example']
def get(**kw):
q = p.urlencode(kw)
with u.urlopen(f'https://linkzoid.pro/api.php?{q}&key={KEY}', timeout=30) as r:
d = json.load(r)
if not d['ok']:
raise SystemExit(d)
return d
gap = get(action='intersect', q=','.join(RIVALS), per=1000)['rows']
mine = {r.get('domain') for r in get(action='refdomains', q=ME, per=1000)['rows']}
fresh = [r.get('domain') for r in gap if r.get('domain') not in mine]
scores = get(action='bulk_dr', domains=','.join(fresh[:2000]))['rows']
with open('prospects.csv', 'w', newline='') as f:
wr = csv.writer(f)
for row in scores:
wr.writerow([row.get('domain'), row.get('dr')])
print(len(fresh), 'candidates')
Worked example, hypothetical numbers
Invented run for a small niche blog; yours will differ| Step | Rows out | Credits |
|---|
| intersect of 3 rivals | 640 domains | 2 |
|---|
| Minus your own referring domains | 410 left | 2 |
|---|
| bulk_dr on the 410 | 410 scored | 1 |
|---|
| Keep DR 20 and above | about 120 | 0 |
|---|
| Hand-check the top 30 | 30 pages opened | 0 |
|---|
From CSV to outreach, without spamming anyone
01Sort by overlap
Domains that link to two or three of your rivals are the ones with a topical reason to link to you. Put them first.
02Open thirty by hand
Look at the page that links to the rival. Is it a resource list, a review, a news item? Only some of these accept a new entry.
03Write one line of reason
Say what your page adds that the rival's page does not. If you cannot say it in a sentence, skip that site.
04Log what you sent
Add columns for date, contact and result to the same CSV, and commit it. Next quarter you will thank yourself.
Mistakes and fixes
Prospecting scripts go wrong in the same few places| Mistake | Why it hurts | Fix |
|---|
| Sorting by DR alone | Big directories and scrapers float to the top | Sort by overlap count first, DR second |
|---|
| Mailing everything above a cutoff | Reads like spam, costs goodwill | Open the top 30 by hand |
|---|
| URL-encoding by hand | Commas and slashes break the query | Use urllib.parse.urlencode |
|---|
| Sending 3,000 domains in one call | Over the 2,000 limit | Chunk the list, one credit per chunk |
|---|
| Trusting DR as quality | It is a log-scale count of referring domains | Treat it as a sort key, not a verdict |
|---|
A word on what DR can and cannot say
DR here is round(100 times log(ref_domains + 1) over log(20,000,000)). It rises with referring domains and nothing else. Keep that in mind. A site can sit at 55 and still be useless to you.
Use it to rank, then read. Look at what the site publishes, whether it links out to a hundred unrelated shops, and whether anything on it was updated since the March 2024 core update. Those checks take a minute per site and no script replaces them.
Once the list is clean, keep it as a dated file and rerun in a month. The Actions runbook shows how to schedule it, and the n8n comparison covers the no-code route if your outreach person prefers it.
Rate and size notesEach call returns up to 1,000 rows and is billed once, so paging through 5,000 intersect rows costs 10 credits, or $0.001. Deep pagination stops at 50,000 rows. Use sort and order=desc on the server rather than sorting a huge list in Python afterwards.