Tutorial
Enrich a Domain CSV with SEO Data in Python Without Losing Unknowns
Add RankParse authority, referring-domain, popularity and registration fields to a CSV while preserving missing data and keeping business qualification apart.
By Abhi Bavishi, Updated , 6 min read
A CSV of company domains can benefit from SEO context: how many referring domains appear in a snapshot, whether a popularity rank is available, and what registration data can be retrieved. Those fields do not tell you whether a company has budget, fits your offer or deserves an email.
This tutorial adds RankParse's domain data to a CSV while preserving missing values and the original input. The outcome is an enriched research file, not an automatically qualified lead list. The code is an illustrative implementation, not a claimed live run or a measured conversion improvement.
Keep enrichment separate from qualification
Start with the business criteria your team actually uses, such as relevant industry, geography, product fit or a documented need. Keep those columns in the input file. SEO signals can add context, but they should not replace the criteria.
A newly registered domain could represent a new business, a rebrand or a migration. A domain outside a popularity list may be a perfectly suitable specialist company. A high authority score does not establish that a website is active or that the company is a good customer.
If the list is for link research rather than sales, use the prospecting workflow to define qualification before sorting it.
What the endpoint can add
The domain-authority endpoint documents these fields:
| Field | Useful interpretation | Inference to avoid |
|---|---|---|
score | RankParse's own authority metric | Moz DA, company quality or buying intent |
referring_domains | Referring domains represented by the source graph | An exhaustive current count of all links on the web |
popularity_rank | Position in the supported Tranco list, when present | Revenue, organic traffic or proof of legitimacy |
registered_at | Available RDAP registration date | The company's founding date |
partial | Part of the result degraded or is incomplete | Every field is equally reliable |
The source data has different update schedules. Link signals use a quarterly snapshot; registration and popularity enrichment have their own caching or refresh behavior. Check the endpoint documentation when those differences matter to your analysis.
A null authority score is unknown. A zero can represent no data in the snapshot. Preserve both accurately. Neither should automatically trigger “reject this business.”
Prepare the input
Use a CSV with one domain column containing bare domains, such as example.com, and any existing business fields. Check duplicate domains, mixed subdomain scopes and pasted URLs before running the lookup.
Install the rankparse SDK and set RANKPARSE_API_KEY as described in the documentation. The script below makes sequential requests rather than introducing concurrency into a small research job. It writes to a new file and retains every original row, including rows with SDK or network request failures. Unexpected response formats, local file errors and process interruptions can still stop the run; keep the original input so you can resume safely.
import csv
import os
import time
from datetime import datetime, timezone
from rankparse import RankParseClient
from httpx import RequestError
from rankparse.errors import RankParseError, AuthError, InsufficientCreditsError
extra_fields = [
"rp_authority", "rp_referring_domains", "rp_popularity_rank",
"rp_registered_at", "rp_partial", "rp_status", "rp_retrieved_at",
]
with open("prospects.csv", newline="", encoding="utf-8") as source:
reader = csv.DictReader(source)
original_fields = list(reader.fieldnames or [])
if "domain" not in original_fields:
raise SystemExit("Input must contain a domain column")
if set(original_fields) & set(extra_fields):
raise SystemExit("Input already has enrichment columns; use the original file")
rows = list(reader)
with RankParseClient(api_key=os.environ["RANKPARSE_API_KEY"]) as client:
with open("prospects_enriched.csv", "w", newline="", encoding="utf-8") as target:
writer = csv.DictWriter(target, fieldnames=original_fields + extra_fields)
writer.writeheader()
blocked = False
for row in rows:
output = dict(row)
domain = row["domain"].strip().lower()
output["rp_retrieved_at"] = datetime.now(timezone.utc).isoformat()
if blocked:
output["rp_status"] = "not_queried_account_check_required"
elif not domain or "://" in domain or "/" in domain:
output["rp_status"] = "check_input"
else:
try:
result = client.domain_authority(domain)
data = result.get("data") or {}
output.update({
"rp_authority": data.get("score"),
"rp_referring_domains": data.get("referring_domains"),
"rp_popularity_rank": data.get("popularity_rank"),
"rp_registered_at": data.get("registered_at"),
"rp_partial": result.get("partial", False),
"rp_status": "unknown" if data.get("score") is None else "returned",
})
except (AuthError, InsufficientCreditsError):
output["rp_status"] = "account_check_required"
blocked = True
except (RankParseError, RequestError):
output["rp_status"] = "lookup_failed"
finally:
time.sleep(1.1)
writer.writerow(output)The pause reduces request frequency for this script. Other jobs sharing the same key can still cause rate limits. Review rate limiting and errors before scheduling larger runs or adding retries.
The example retains rows affected by SDK errors, including rate limits and not-found responses, or HTTP transport failures instead of converting those failures into zeroes. An account-level problem stops further lookups while preserving the remaining input rows. Inspect the status column and resolve failures before interpreting the file; a production workflow should also retain appropriate error details and resumable progress.
Read the result without turning absence into judgment
Consider these fictional output cases:
| Result | What you know | What to do |
|---|---|---|
| Score returned, registration date blank, partial true | Some enrichment may be missing | Use available fields cautiously; check the missing registration information if necessary |
| Score null or lookup failed | Authority was not established | Retry or leave unknown; do not assign a low-quality label |
| Score zero and no referring domains returned | The snapshot did not provide a positive link signal | Investigate coverage and the actual website if the company otherwise fits |
| High score, business fit unconfirmed | The provider returned a strong authority measurement | Complete the same business-fit review as for any other company |
CSV blanks preserve missing values for human review, but spreadsheet software may interpret blanks differently in formulas. Check filters and scoring rules before using the file. Keep the provider prefix in column names so a future export from Moz or Ahrefs cannot silently overwrite a different metric.
Add human or agent review after the export
Review a small mix of returned, unknown and low-score rows. Open the websites and compare the enrichment with your business criteria. If a rule rejects otherwise relevant companies, fix the rule before processing the rest of the list.
Claude or another connected client can help organize that review, provided you share only the fields needed for the task. With RankParse MCP available, ask for missing evidence rather than a verdict:
Review these domain-enrichment rows against the business criteria I provide. Separate business fit from SEO measurements. Keep unknown values unknown. For each unresolved row, identify the next useful check; do not infer revenue, legitimacy or buying intent from authority, popularity or domain age.
For a connector-supported workflow, follow the MCP documentation. A chat interface does not change the limits of the underlying data.
What to build next
If the enriched list supports a real decision, add only the next field needed to resolve an uncertainty. A backlink sample may help understand who references a website; it does not prove customer fit. Keep the original CSV, the enriched version and a note of the criteria used so another teammate can review your choices.