Skip to main content

Competitive position across topics

The dashboard’s Industry rankings widget shows your top-mentioned competitors across all of your tracked conversations. Sometimes you want the finer-grained view: for each topic you track, where do you actually rank? This recipe uses tpc analytics explore to answer that in one script — no dashboard clicking required.

Prerequisites

  • The CLI installed and authenticated. See Installation and Authentication.
  • tpc product switch <product-slug> set to the product you want to check.
  • jq installed locally.

The script

Each topic requires its own ranking lookup, so this runs them concurrently instead of one at a time — each result is captured to a temp file so parallel output doesn’t interleave, then printed back in the original topic order.
#!/usr/bin/env bash
set -euo pipefail

YOUR_PRODUCT=$(tpc auth whoami | awk -F': ' '/^Product:/{print $2}')

tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT

check_topic() {
  local topic_id="$1" topic="$2"
  local you
  you=$(tpc analytics explore --metric sov --by competitor --topic "$topic_id" --top 100 --json \
    | jq -r --arg name "$YOUR_PRODUCT" '.rows[] | select(.label == $name) | "\(.rank)\t\(.sov)"')
  if [ -n "$you" ]; then
    local rank sov
    rank=$(echo "$you" | cut -f1)
    sov=$(echo "$you" | cut -f2)
    printf "%-14s rank #%-4s sov %s%%\n" "$topic" "$rank" "$sov"
  else
    printf "%-14s not in top 100\n" "$topic"
  fi
}

topic_ids=()
while IFS=$'\t' read -r topic_id topic; do
  topic_ids+=("$topic_id")
  check_topic "$topic_id" "$topic" > "$tmpdir/$topic_id" &
done < <(tpc analytics explore --metric sov --by topic --json | jq -r '.rows[] | [.key, .label] | @tsv')

wait

for topic_id in "${topic_ids[@]}"; do
  cat "$tmpdir/$topic_id"
done
Run it:
chmod +x competitive-position.sh
./competitive-position.sh
Example output:
comparison     rank #1    sov 58.8%
feature        rank #2    sov 42.4%
use-case       rank #3    sov 36.0%
budget         rank #2    sov 34.2%
industry       rank #22   sov 18.0%

How it works

  1. tpc auth whoami prints your active product’s name, which is what you look for in each topic’s ranking.
  2. tpc analytics explore --metric sov --by topic lists every topic you track, with each topic’s ID (key) and name (label).
  3. For each topic, a background check_topic call runs tpc analytics explore --metric sov --by competitor --topic <topicId> — the same ranking view as the dashboard’s Industry rankings widget, but scoped to one topic instead of everything. All topics are looked up concurrently instead of waiting on each one in turn.
  4. jq picks out the row matching your product’s name and writes its rank and share of voice to that topic’s temp file.
  5. wait blocks until every background lookup finishes, then the results are printed back in the original topic order (not finish order).
The speedup scales with how many topics you track. With a handful of topics, most of the wall-clock time is per-invocation overhead (auth and org resolution), so parallelizing saves less than you’d expect. With dozens of topics, running them concurrently instead of sequentially is the difference between minutes and seconds.
--top 100 is the highest page size the API allows in one page. If a topic has more than 100 tracked competitors and you don’t show up, page through with --page 2 (see tpc analytics explore --help) rather than assuming you’re unranked.

Variations

Just want the overall ranking, not broken out by topic?
tpc analytics explore --metric sov --by competitor --last 30d
Want the raw JSON for a dashboard or Slack digest instead of a formatted table? Drop the printf lines and pipe the jq output directly — every command in this recipe supports --json. Only care about a couple of topics? Skip the topic-listing step and hardcode the topic IDs you already know:
tpc analytics explore --metric sov --by competitor --topic <topicId>

Show competitors around your rank

Knowing your rank and share of voice in a topic is useful, but it doesn’t say who you’re actually competing against right at that position. This script takes one topic and shows the competitors ranked immediately above and below you — reusing the exact same tpc analytics explore --by competitor --topic response as the main script above, since every competitor’s rank is already in that one call. No extra API request needed.
#!/usr/bin/env bash
set -euo pipefail

TOPIC_ID="$1"
WINDOW="${2:-2}"

YOUR_PRODUCT=$(tpc auth whoami | awk -F': ' '/^Product:/{print $2}')

rows=$(tpc analytics explore --metric sov --by competitor --topic "$TOPIC_ID" --top 100 --json \
  | jq -r --arg name "$YOUR_PRODUCT" --argjson window "$WINDOW" '
      .rows as $rows
      | ($rows | map(.label) | index($name)) as $idx
      | if $idx == null then empty else
          $rows[(if $idx - $window < 0 then 0 else $idx - $window end):($idx + $window + 1)][]
          | [.rank, .label, .sov, (if .label == $name then "you" else "" end)] | @tsv
        end
    ')

if [ -z "$rows" ]; then
  echo "$YOUR_PRODUCT is not in the top 100 for this topic"
  exit 0
fi

echo "$rows" | while IFS=$'\t' read -r rank label sov marker; do
  if [ "$marker" = "you" ]; then
    printf "%-4s %-20s %s%%  <-- you\n" "$rank" "$label" "$sov"
  else
    printf "%-4s %-20s %s%%\n" "$rank" "$label" "$sov"
  fi
done
Run it with a topic ID (get one from tpc analytics explore --metric sov --by topic --json, or from the topic-listing step of the script above):
chmod +x competitors-around-rank.sh
./competitors-around-rank.sh a8bbcb6f-1ee3-462b-98f1-abe8e05e5437
Example output:
19   MongoDB              21.15%
20   Cassandra            19.23%
21   Planetscale          19.23%  <-- you
22   AlloyDB              17.31%
23   ClickHouse           17.31%
Pass a second argument to widen or narrow the window (default is 2 rows on each side):
./competitors-around-rank.sh a8bbcb6f-1ee3-462b-98f1-abe8e05e5437 5
If you’re ranked #1 (or near the bottom of the tracked list) in a topic, the window just clamps to whatever rows exist in that direction — you’ll see fewer neighbors on that side, not an error.

All topics, with competitors around your rank

Combines both scripts above: loop every topic concurrently (like the first script), but show the window of competitors around your rank in each one (like the one above) instead of just your own row. Same parallel-lookup structure — background jobs writing to per-topic temp files, replayed in original order — just with more rows per topic.
#!/usr/bin/env bash
set -euo pipefail

WINDOW="${1:-2}"

YOUR_PRODUCT=$(tpc auth whoami | awk -F': ' '/^Product:/{print $2}')

tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT

check_topic() {
  local topic_id="$1" topic="$2"
  local rows
  rows=$(tpc analytics explore --metric sov --by competitor --topic "$topic_id" --top 100 --json \
    | jq -r --arg name "$YOUR_PRODUCT" --argjson window "$WINDOW" '
        .rows as $rows
        | ($rows | map(.label) | index($name)) as $idx
        | if $idx == null then empty else
            $rows[(if $idx - $window < 0 then 0 else $idx - $window end):($idx + $window + 1)][]
            | [.rank, .label, .sov, (if .label == $name then "you" else "" end)] | @tsv
          end
      ')

  echo "$topic"
  if [ -z "$rows" ]; then
    printf "  %s not in top 100\n" "$YOUR_PRODUCT"
  else
    echo "$rows" | while IFS=$'\t' read -r rank label sov marker; do
      if [ "$marker" = "you" ]; then
        printf "  %-4s %-20s %s%%  <-- you\n" "$rank" "$label" "$sov"
      else
        printf "  %-4s %-20s %s%%\n" "$rank" "$label" "$sov"
      fi
    done
  fi
  echo
}

topic_ids=()
while IFS=$'\t' read -r topic_id topic; do
  topic_ids+=("$topic_id")
  check_topic "$topic_id" "$topic" > "$tmpdir/$topic_id" &
done < <(tpc analytics explore --metric sov --by topic --json | jq -r '.rows[] | [.key, .label] | @tsv')

wait

for topic_id in "${topic_ids[@]}"; do
  cat "$tmpdir/$topic_id"
done
Run it:
chmod +x competitive-position-with-window.sh
./competitive-position-with-window.sh
Pass a window size as the first argument (default 2):
./competitive-position-with-window.sh 5
Example output:
comparison
  1    Planetscale          58.82%  <-- you
  2    Vitess               47.06%
  3    MySQL                44.12%

feature
  1    PostgreSQL           45.45%
  2    Planetscale          42.42%  <-- you
  3    MySQL                42.42%
  4    Google Cloud Spanner 33.33%

use-case
  1    Amazon Aurora        38%
  2    Redis                38%
  3    Planetscale          36%  <-- you
  4    Google Cloud Spanner 34%
  5    AWS                  34%

budget
  1    PostgreSQL           34.15%
  2    Planetscale          34.15%  <-- you
  3    Google Cloud SQL     31.71%
  4    Neon                 31.71%

industry
  19   MongoDB              21.15%
  20   Cassandra            19.23%
  21   Planetscale          19.23%  <-- you
  22   AlloyDB              17.31%
  23   ClickHouse           17.31%
Firing one concurrent request per topic can occasionally trip the API’s rate limit (429 Too many requests) if you’re re-running the script repeatedly in quick succession, for example while iterating on it. Wait a few seconds and retry — it’s a rate limit on request volume, not a problem with your data or account.