> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rankraft.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Competitor leaderboard

> Rank yourself against your confirmed competitors by any visibility metric, for any period or engine.

The leaderboard on the Competitors page is the visibility report with `brands: "all"`: one row per brand, you plus every confirmed competitor, each with its `rank` by Visibility Score.

## How this example works

1. **`brands: "all"`** returns you and every confirmed competitor. Your row has `brand.owned: true`.
2. **`rank`** is by Visibility Score, 1 = best. To order by another metric, pass `sort` or sort in your code. Use descending order for rates and the score, and **ascending** for `average_position`, where lower is better.
3. **One page is enough.** A leaderboard holds you plus your confirmed competitors, well under the 100-row page size.

```js JavaScript theme={"system"}
import { RankRaft } from "rankraft-js";

const rr = new RankRaft();

const page = await rr.reports.visibility({
  site_id: process.env.RANKRAFT_SITE_ID,
  start_date: "2026-09-01",
  end_date: "2026-09-30",
  brands: "all",
  metrics: ["visibility_score", "share_of_voice", "mention_rate", "average_position"],
  limit: 100,
});

for (const row of page.data) {
  const you = row.brand.owned ? "  ← you" : "";
  const pos = row.average_position === null ? "—" : row.average_position.toFixed(1);
  console.log(
    `${String(row.rank).padStart(2)}. ${row.brand.name.padEnd(24)} score ${String(row.visibility_score).padStart(3)}` +
      `  SoV ${(row.share_of_voice * 100).toFixed(1)}%  position ${pos}${you}`,
  );
}

// By another metric: lower position is better, so ascending, with never-named brands last.
const byPosition = [...page.data].sort((a, b) => (a.average_position ?? Infinity) - (b.average_position ?? Infinity));
```

```python Python theme={"system"}
import os
from rankraft import RankRaft

with RankRaft() as rr:
    page = rr.reports.visibility(
        site_id=os.environ["RANKRAFT_SITE_ID"],
        start_date="2026-09-01",
        end_date="2026-09-30",
        brands="all",
        metrics=["visibility_score", "share_of_voice", "mention_rate", "average_position"],
        limit=100,
    )

for row in page:
    you = "  ← you" if row["brand"]["owned"] else ""
    pos = "—" if row["average_position"] is None else f"{row['average_position']:.1f}"
    print(f"{row['rank']:>2}. {row['brand']['name']:<24} score {row['visibility_score']:>3}"
          f"  SoV {row['share_of_voice']:.1%}  position {pos}{you}")

# By another metric: lower position is better, so ascending, with never-named brands last.
by_position = sorted(page.data, key=lambda r: (r["average_position"] is None, r["average_position"] or 0))
```

```bash curl theme={"system"}
curl https://api.rankraft.ai/v1/reports/visibility \
  -H "X-API-Key: $RANKRAFT_API_KEY" -H "Content-Type: application/json" \
  -d '{"site_id":"'$RANKRAFT_SITE_ID'","start_date":"2026-09-01","end_date":"2026-09-30",
       "brands":"all","limit":100,
       "metrics":["visibility_score","share_of_voice","mention_rate","average_position"]}'
```

## Per engine

Add `group_by: ["platform"]` and `rank` restarts within each engine, so you can see where a competitor leads and where you do. Rows come sorted by engine, then rank.

## Only some brands

Pass a list instead of `"all"`: `brands: ["Misali Foods", "Shan Foods"]`. Names match your brand or a confirmed competitor, ignoring case. `rank` is still the brand's position among **everyone**, not among the brands you listed. A name that matches neither returns no row, so check that every brand you asked for came back.

## With change

Run the same call for the previous window ([how to compute it](/cookbook/conventions#dates-are-inclusive-utc-days)) and join on `brand.name` to show each brand's change in score and in rank.

> [!NOTE]
>
> Unconfirmed competitors are measured but not ranked. Confirm them on the Competitors page and they appear here, for past ranges too. See [Why past numbers change](/cookbook/why-past-numbers-change).

## Common follow-ups

> **[Compare competitors over time](/cookbook/compare-competitors)**
>
> The same brands, day by day.

> **[Your brand, domains and competitors](/cookbook/brand-and-competitors)**
>
> Who is confirmed, and their domains.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.