Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.tryprofound.com/llms.txt

Use this file to discover all available pages before exploring further.

The “Citation Rank” / “Citation Share by Domain” panel in the Profound app is the citations endpoint grouped by root_domain, sorted by citation_share descending, with each row showing the change in share vs the previous window. Two calls (current + prior), merge by domain, diff the shares.

How this example works

  1. dimensions: ["root_domain"] — one row per cited domain in each call. Run both the current and prior windows.
  2. Merge by domain. For each current-window row, look up the previous-window share (default 0 if missing) and diff.
  3. Sort by current citation_share descending to match the UI.
count and citation_share measure different things. count is the raw number of citations to that domain in the window. citation_share is count / total_citations per AI model, then averaged across models. A domain cited heavily on a low-volume model (e.g. Perplexity) can have a higher share than a domain with more total citations spread across high-volume models — the two columns won’t sort in lockstep. Pick the one that matches the question you’re answering and sort on it.
import os
from datetime import date, timedelta
from profound import Profound

client = Profound(api_key=os.environ["PROFOUND_API_KEY"])

# What to fetch — replace with your own values.
CATEGORY_NAME = "<your-category-name>"
DAYS          = 7
INCLUSIVE_END = date(2026, 5, 11)    # the last day of your current window
TOP_N         = 10


def get_domain_shares(category_id, start, end):
    """Return {domain: share} for every cited domain in the window."""
    res = client.reports.citations(
        category_id=category_id,
        start_date=start.isoformat(),
        end_date=end.isoformat(),
        metrics=["count", "citation_share"],
        dimensions=["root_domain"],
        filters=[{"field": "prompt_type", "operator": "is", "value": "visibility"}],
        pagination={"limit": 50000, "offset": 0},
    )
    m = res.info.query["metrics"]
    d = res.info.query["dimensions"]
    i_count  = m.index("count")
    i_share  = m.index("citation_share")
    i_domain = d.index("root_domain")
    return {
        row.dimensions[i_domain]: {
            "count": row.metrics[i_count],
            "share": row.metrics[i_share],
        }
        for row in res.data
    }


def current_and_prior_windows(inclusive_end, days):
    """Two (start, end_exclusive) pairs of equal length, back-to-back."""
    current = (
        inclusive_end - timedelta(days=days - 1),
        inclusive_end + timedelta(days=1),     # +1 day → exclusive end
    )
    prior = (current[0] - timedelta(days=days), current[0])
    return current, prior


def find_category_id(name):
    """Return the UUID of the category whose name matches (case-insensitive)."""
    for c in client.organizations.categories.list():
        if c.name.lower() == name.lower():
            return c.id
    raise ValueError(f"No category named {name!r}")


# Resolve name → ID, run current + prior, then build the leaderboard with deltas.
category_id    = find_category_id(CATEGORY_NAME)
current, prior = current_and_prior_windows(INCLUSIVE_END, DAYS)

current_domains = get_domain_shares(category_id, *current)
prior_domains   = get_domain_shares(category_id, *prior)

rows = sorted(
    (
        {
            "domain":    name,
            "count":     d["count"],
            "share":     d["share"],
            "delta_pp":  (d["share"] - prior_domains.get(name, {"share": 0})["share"]) * 100,
        }
        for name, d in current_domains.items()
    ),
    key=lambda r: r["share"],
    reverse=True,
)[:TOP_N]

for rank, r in enumerate(rows, start=1):
    sign = "+" if r["delta_pp"] >= 0 else "−"
    delta_str = f"{sign}{abs(r['delta_pp']):.1f} pp"
    print(f"{rank:>2}. {r['domain']:<32} {r['share']:>6.1%}  {delta_str}")

Page-level breakdown

Swap root_domain for url in dimensions to get the top citing pages (one row per URL) instead of the top citing domains.