Reverse-Engineering Co-Citation: Find the Pages That Decide Your Category
If you want on the lists an AI hands people, first find the handful of pages it reads before it answers. Here is how to rank them.
When someone asks ChatGPT for the best tool in your category, the model does not consult a scoreboard of vendors. It fires off a few searches, pulls back a set of pages, keeps the ones a reranker judges most relevant, and writes its recommendation from what those pages happen to say. The brands it names are the brands that already appear, in retrievable language, on the pages it pulled. So the practical question behind "how to get on AI recommendation lists" is narrower and more answerable than it sounds. Which specific third-party pages does the model keep reading when it answers for your category, and what do they say about you?
That set of pages is small. For any given category it is a few dozen URLs that recur across prompts and across engines, and most of your outreach effort should go to them and almost nowhere else. The mistake teams make is treating AI visibility as a diffuse content problem, publishing more and hoping. The pages that decide your category are enumerable, they are rankable by how much influence they carry, and once you have that ranking you can pursue each one deliberately. This is a build-along. By the end you will have a scored co-citation table for your own category and a defensible order in which to work it.
The idea: citation co-occurrence as a proxy for retrieval
Start with what you can and cannot see. You cannot watch the candidate set a model assembles inside its retrieval pipeline. What you can see, on Perplexity and on the search modes of the other engines, is the list of URLs the model cites after it answers. Attribution is not identical to retrieval, and a cited page is a page that made it all the way through, but citations are the cleanest window you get from the outside. A URL that gets cited again and again, across different prompts in your category and across different engines, is a URL that keeps landing in candidate sets. That recurrence is the signal worth mining.
Co-citation adds a second dimension. When a page is cited for a prompt that also produces a competitor mention in the answer, that page is part of the evidence the model used to recommend your competitor. Pages that co-occur with competitor names are the rooms where your category's buying decisions get shaped. Ranking by raw citation frequency tells you which pages are load-bearing. Layering in competitor co-occurrence tells you which of those pages are actively working against you right now. Both come out of the same captured data.
Step one: assemble the category prompts
You need a prompt set that reflects how buyers actually ask, not a keyword list. This is the Prompt-Space Coverage idea in miniature, and if you already have that map you can lift the prompts straight from it. Pull real questions from sales-call recordings, support tickets, and your own team typing honest queries into the assistants. Keep them phrased the way a person types, because "cheapest CRM that still does decent reporting for a 10-person team" fans out into different sub-queries than "best CRM." Group them into a few intent shapes: category ("best X for Y"), comparison ("X vs Z"), and problem ("we keep hitting this, what fixes it"). Thirty to fifty prompts across those shapes is enough to expose the surface without burying you in capture work.
Step two: capture cited URLs per prompt, per engine, per run
Run every prompt through the engines you care about, the four being ChatGPT, Claude, Gemini, and Perplexity, and record every cited URL alongside its prompt and engine, plus the run number and date. Two capture habits matter more than the rest.
Run each prompt several times. Retrieval is not deterministic, so a single run tells you what surfaced that once, not what surfaces reliably. Three runs per prompt per engine is a reasonable floor. And record the answer text, or at least a list of which competitor brands the model named, on the same row as the URLs. You need that later to compute co-occurrence. The raw material you are building toward is a flat table of capture events, one row per cited URL per run, that looks roughly like this:
prompt_id, engine, run, date, cited_url, brands_mentioned
p07, perplexity, 1, 2026-08-24, https://www.g2.com/categories/crm, "Salesforce;HubSpot;Pipedrive"
p07, chatgpt, 1, 2026-08-24, https://www.reddit.com/r/sales/comments/abc, "HubSpot;Close"
p07, perplexity, 2, 2026-08-24, https://www.g2.com/categories/crm, "Salesforce;HubSpot"Step three: aggregate into a co-citation ranking
Now collapse those hundreds of rows into a ranking. The counting is simple and worth doing in code so you can rerun it every month against fresh captures. Load the capture log, normalize each URL to its bare form, count how many distinct prompts cite each page and each domain, and tally how often each page co-occurs with a competitor mention.
import csv
from collections import defaultdict
from urllib.parse import urlsplit
COMPETITORS = {"salesforce", "hubspot", "pipedrive", "close", "zoho"}
def canon(u):
parts = urlsplit(u.strip())
path = parts.path.rstrip("/")
return f"{parts.netloc.lower()}{path.lower()}"
def domain(u):
return urlsplit(u.strip()).netloc.lower().replace("www.", "")
page_prompts = defaultdict(set) # url -> set of prompt_ids
page_hits = defaultdict(int) # url -> total citation events
page_engines = defaultdict(set) # url -> set of engines
page_cocite = defaultdict(int) # url -> events sharing a competitor mention
dom_prompts = defaultdict(set) # domain -> set of prompt_ids
with open("captures.csv") as f:
for row in csv.DictReader(f):
url = canon(row["cited_url"])
page_prompts[url].add(row["prompt_id"])
page_hits[url] += 1
page_engines[url].add(row["engine"])
dom_prompts[domain(row["cited_url"])].add(row["prompt_id"])
brands = {b.strip().lower() for b in row["brands_mentioned"].split(";") if b}
if brands & COMPETITORS:
page_cocite[url] += 1
total_prompts = len({p for ps in page_prompts.values() for p in ps})
ranked = sorted(page_prompts, key=lambda u: (len(page_prompts[u]), page_hits[u]),
reverse=True)
print(f"{'page':45} {'prompts':>7} {'hits':>5} {'eng':>4} {'competitor%':>11}")
for url in ranked[:20]:
reach = len(page_prompts[url]) / total_prompts
comp = page_cocite[url] / page_hits[url]
print(f"{url[:45]:45} {len(page_prompts[url]):7} {page_hits[url]:5} "
f"{len(page_engines[url]):4} {comp:11.0%}")Two design choices in there are deliberate. The primary sort key is the count of distinct prompts a page is cited for, not the raw hit count, because a page cited fifty times for one weird phrasing matters less than a page cited across a dozen different questions. Reach across your prompt space is the thing that predicts influence. The engine count is a tie-breaker worth surfacing, since a page all four engines lean on is more durable than one only Perplexity happens to like this month.
Step four: read the co-citation table
Here is the top slice of an output table for a hypothetical CRM category, thirty prompts, four engines, three runs each.
| Page | Prompts | Hits | Engines | Competitor % |
|---|---|---|---|---|
| g2.com/categories/crm | 24 | 71 | 4 | 88% |
| reddit.com/r/sales (pinned thread) | 19 | 44 | 3 | 64% |
| yourcompetitor.com/vs/you | 11 | 22 | 2 | 100% |
| techradar.com/best-crm | 14 | 31 | 4 | 71% |
| en.wikipedia.org/wiki/Customer_relationship_management | 9 | 18 | 4 | 12% |
| yourblog.com/crm-guide | 6 | 9 | 2 | 0% |
Read it top down and the priorities almost write themselves. The G2 category page is the spine of this category: cited for 24 of 30 prompts, present on all four engines, and co-occurring with a competitor in 88 percent of its citations. Whatever G2 says about you is close to what the models say about you, and right now that page is mostly recommending other people. The Reddit thread is the second pillar, softer and messier, cited widely and carrying competitor mentions two-thirds of the time.
The third row is the one that should sting. A competitor's own comparison page, "yourcompetitor.com/vs/you," is getting cited for a third of your prompts and co-occurs with a competitor in every single citation, because it is a competitor's page by construction. The model is reading your rival's framing of the matchup and passing it along. Wikipedia sits high on reach but near zero on competitor co-occurrence, which marks it as neutral reference rather than a recommendation surface, useful for factual accuracy and not a place to compete. Your own blog post sits at the bottom, exactly the inversion the third-party-share research keeps finding: third-party pages often carry a substantial share of brand mentions, a pattern you should quantify with your own table rather than assume.
Step five: score influence against addressability
Frequency tells you where the influence sits. It says nothing about whether you can do anything about it. So add a second axis and score every top page on how addressable it is, on a plain four-level scale.
- You own it. Your site, your docs, your comparison pages. Full control, lowest excuse for leaving it wrong.
- You can pitch it. Review platforms where you claim a profile, directories that take vendor submissions, journalists and analysts you can contact with real information.
- Open community. Reddit, Stack Overflow, Q&A sites where anyone can contribute a genuinely useful answer under their own name, subject to the community's norms.
- Hard. An independent reviewer's editorial roundup, an unaffiliated blogger's deep dive. No submission form, no lever except being worth including.
Now cross the two axes. A high-influence, high-addressability page is where you start, because the return is large and the path is short. A high-influence, hard page is a long campaign, the kind you earn over quarters. A low-influence page is a distraction regardless of how easy it is to change, and this is where scattershot outreach dies, in the low-left corner fixing pages nobody's model reads. Sort your table by influence, tag each row with an addressability level, and the work order falls out: influential and reachable first, influential and hard as a running program, everything else later or never.
Using the ranking without crossing the line
The ranking hands you three honest moves, and it helps to name them because they are different acts with different ethics.
Get listed where you are absent. A high-influence page that never mentions you is the most common finding and often the best opportunity, because these are the conversations where buyers get advice and you are not named. On a page you can pitch, that means claiming the profile or submitting through the front door. On a hard page, it means shipping the thing that earns the mention and giving the reviewer real access, which is slower and more durable.
Get corrected where you are wrong. Pages go stale. Your pricing is two versions old, a comparison gets your core feature backward, a directory still calls you a startup three years on. Durable pages can remain in citation sets long after their facts drift, so stale-but-ranking sources are normal and fixable. On community and reference pages, a factual correction with a source is welcome. A promotional rewrite is not, and the distinction is the whole ethic.
Earn inclusion where you genuinely belong. The Princeton and IIT Delhi GEO study tested what actually raises visibility in generative answers, and the methods that worked were adding citations, adding statistics, and adding direct quotations, along with cleaner writing, for up to roughly a 40 percent lift on their metric. Keyword stuffing did nothing or slightly hurt. Every method that worked amounts to making a page more genuinely informative and better sourced. That is the boundary in one sentence. Planting fake reviews, running sockpuppet accounts, or buying placements dressed as independent opinion is a different activity, and beyond the ethics, the engines and the platforms keep getting better at discounting manufactured signal. Accuracy compounds. Manipulation is a liability with a delay on it.
Keeping the table alive
One capture pass is a photograph of a moving thing. The co-citation table you build this week describes a category that will have shifted by next quarter, as new roundups get published, threads age out, engines reweight their sources, and competitors earn placements you are absent from. The gap between the pages that could answer your category and the smaller set actually retrieved, the Retrieval Gap, does not hold still. Rerunning the Python against a fresh capture log every month is what keeps the ranking honest, and the whole method maps onto the middle of the AI Visibility Funnel: capturing citations measures Candidacy and Citation, and the outreach you prioritize from the table lifts Retrievability upstream of both. A tool like shareof.ai exists to run that capture-and-rank loop continuously across engines, but nothing here needs it. A spreadsheet, thirty prompts, and the script above will hand you a ranked, addressability-scored map of exactly which pages decide your category, and running it by hand once teaches you more than any dashboard.
A note on measurement
Treat the numbers in the worked example as illustrative and the outside figures as correlational. The 80-to-85 percent third-party share, the 17-year source age, the 40 percent GEO lift: these come from specific datasets and specific methods, and your category may sit well off any of them. The point of building your own table is that the answer is different for every category, and the only trustworthy version is the one you captured. Weight your priorities toward pages that recur across runs and engines rather than the one that surfaced in a single lucky query, because retrieval noise will otherwise send you chasing ghosts. The ranked table is a hypothesis about where AI finds you. The listings you claim, the corrections you file, and the roundups you finally earn your way onto are how you test it.
Primary sources and evidence
- OpenAI web search tool — source annotations and grounded responses.
- Gemini grounding with Google Search — search grounding and citation metadata.
- Perplexity Search API — retrieving ranked web results programmatically.
Continue through the system
- Map Your Citation Surface: Every Page Where AI Can Find You
- What to Do When a Competitor Owns the AI Answer for Your Category
- Measure Your Own Share of Retrieval With the Model APIs
Run the practical layer with the free AI visibility scan, explore the AI search library, or see the AI visibility benchmarks.