Blog

Tutorial

Export a Competitor Backlink Gap to a Reviewable CSV with Python

Use RankParse's Python SDK to export a bounded competitor backlink gap, preserve sample and scoring limits, and prepare candidates for careful editorial review.

By Abhi Bavishi, Updated , 5 min read

A competitor-gap export is a starting point for research. It identifies domains observed linking to a comparison site but not to yours in the dataset. It does not establish that those sites should link to you, that a link is attainable, or that no link to your site exists today.

This tutorial uses RankParse's Python SDK to produce a CSV with the evidence needed to review that distinction. It keeps the extraction narrow; for the broader prospecting process, read how to find link-building opportunities.

Choose a comparison that answers a real question

Pick one competitor with a similar audience or a useful competing resource. A famous domain with a large link profile may return impressive names without helping your research.

Write down the resource you would want a publication to consider and why its readers might benefit. If you cannot describe that value yet, treat the export as content research rather than an outreach list.

The example script below accepts your own domains. It has not been executed against live accounts for this article, and no result counts or outreach outcomes are claimed.

Understand the sample before exporting it

RankParse's competitor-gap endpoint uses a quarterly link-graph snapshot. According to the endpoint documentation, it considers at most 1,000 competitor referring-domain candidates, scores up to 250 remaining candidates, and returns up to 200 rows. Generic hosting platforms are excluded by default.

That has practical consequences:

  • partial: true means the result may not cover all gaps. It can still contain scored candidates.
  • scored: false means authority scoring did not complete. The score field's zeroes are placeholders, not valid authority measurements.
  • total is a lower bound when the response is partial. returned describes the returned rows.
  • crawl_release identifies the underlying snapshot, not the time a link was first created.

The server's default score ordering is a convenience for browsing results. It is not an editorial priority ranking. A highly relevant niche site with a lower score may deserve attention before a large unrelated publication.

Write the CSV without discarding uncertainty

Install the rankparse SDK and set RANKPARSE_API_KEY using the getting-started documentation. Keep credentials outside the script and source control.

Save this example as export_gap.py. It performs one bounded lookup and writes the response flags alongside every candidate so they remain visible in a spreadsheet.

import csv
import os
import sys
from datetime import datetime, timezone
from rankparse import RankParseClient

if len(sys.argv) != 3:
    raise SystemExit("Usage: python export_gap.py YOUR_DOMAIN COMPETITOR_DOMAIN")

you, competitor = sys.argv[1:]
with RankParseClient(api_key=os.environ["RANKPARSE_API_KEY"]) as client:
    result = client.competitor_gap(you, vs=competitor, limit=50)

observed_at = datetime.now(timezone.utc).isoformat()
scored = result.get("scored") is True
fields = [
    "our_domain", "competitor", "linking_domain", "observed_links",
    "rankparse_authority", "scored", "partial", "crawl_release",
    "retrieved_at", "source_page", "relevance_notes", "next_check",
]

with open("gap_review.csv", "w", newline="", encoding="utf-8") as handle:
    writer = csv.DictWriter(handle, fieldnames=fields)
    writer.writeheader()
    for row in result.get("data", []):
        writer.writerow({
            "our_domain": you,
            "competitor": competitor,
            "linking_domain": row["from_domain"],
            "observed_links": row.get("total_links"),
            "rankparse_authority": row.get("from_domain_score") if scored else None,
            "scored": scored,
            "partial": result.get("partial"),
            "crawl_release": result.get("crawl_release"),
            "retrieved_at": observed_at,
            "next_check": "Locate and inspect the relevant linking page",
        })

print(f"Saved {len(result.get('data', []))} candidates to gap_review.csv")
print(f"Partial: {result.get('partial')}; scored: {scored}")

Run it with bare domains, without schemes or paths. The script intentionally leaves the source-page and relevance columns blank: the gap response contains domains, not enough page evidence to fill them responsibly.

An empty file with a header means no rows were returned; it does not prove that all relevant publications already link to you. Review the target, competitor and dataset coverage before drawing that conclusion.

This is a minimal extraction example. For scheduled work, handle authentication, insufficient balance, rate limiting and transient errors explicitly using the error reference. A failed request should not silently become an empty successful export.

Review a small sample before expanding

Open the CSV and inspect several candidates. Locate a relevant linking page, check that it remains accessible, and record what it actually references. Preserve the difference between a snapshot observation and your current page inspection.

For each candidate, answer:

  1. Does the publication serve a relevant audience?
  2. What is the existing link doing for the reader?
  3. Does our resource add something distinct and useful in that context?
  4. Is there already a reference to our site that the sampled comparison missed?
  5. What evidence or asset is still needed before deciding on outreach?

Do not automatically reject everything below a score threshold. Do not treat repeated links as repeated editorial endorsements: a sitewide template can create many rows. Use backlink-quality checks to assess the placement itself.

Hand the review to Claude if conversation is easier

With RankParse MCP connected, you can ask Claude to use the corresponding get_competitor_gap tool:

Compare [our domain] with [competitor], returning at most 50 candidate domains. Preserve partial, scored and snapshot information. Do not qualify prospects by authority alone. Produce a review table with source page, relevance hypothesis, missing evidence and next check. Leave unavailable evidence blank rather than inventing it.

The same sampling limits apply. Ask before expanding the research and inspect the tool outputs behind the summary. A conversational interface does not make the dataset exhaustive.

For a repeatable agent workflow, use the Claude research-assistant guide. Keep the CSV when you need consistent records across sessions.

What to build next

Once a small sample proves useful, repeat the extraction for another relevant competitor and deduplicate candidates by domain while preserving which comparison produced them. Do not overwrite earlier evidence or assume a new export means the underlying snapshot changed.

Your finished output should be a research queue with traceable evidence. Only the candidates that survive page-level review belong in an outreach plan.

Start free

Let your agent take the first pass.

100 free credits. No card. No seats.