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

# Competitive Analysis

> Track your position against competitors and identify opportunities

Analyze your competitive landscape in AI search results with gap analysis and trend tracking.

<Note>
  This guide uses the API client from the [Guides index](/developers/guides/index#api-client). Copy it to your project first.
</Note>

## What You'll Build

A competitive analysis showing:

* **Competitor ranking**: Share of Voice comparison
* **Gap analysis**: Where you're winning and losing
* **Trend tracking**: Monitor competitor momentum

***

## Get Competitive Landscape

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function getCompetitiveLandscape(client, brandId, period = 30) {
    const data = await client.getCompetitors(brandId, {
      period,
      limit: 20,
      sort: 'shareOfVoice',
      order: 'desc',
    });

    const yourBrand = data.competitors.find(c => c.relationship === 'SELF');
    const competitors = data.competitors.filter(c => c.relationship !== 'SELF');

    if (!yourBrand) {
      throw new Error('Your brand not found in competitor data');
    }

    return {
      yourPosition: {
        name: yourBrand.name,
        shareOfVoice: yourBrand.shareOfVoice,
        mentions: yourBrand.totalMentions,
        avgPosition: yourBrand.avgPosition,
        sentiment: yourBrand.avgSentiment,
        rank: data.competitors.findIndex(c => c.id === yourBrand.id) + 1,
      },

      competitors: competitors.map(c => ({
        id: c.id,
        name: c.name,
        shareOfVoice: c.shareOfVoice,
        mentions: c.totalMentions,
        avgPosition: c.avgPosition,
        sentiment: c.avgSentiment,
        gap: (c.shareOfVoice - yourBrand.shareOfVoice).toFixed(2),
        status: c.shareOfVoice > yourBrand.shareOfVoice ? 'ahead' : 'behind',
      })),

      summary: {
        totalCompetitors: competitors.length,
        competitorsAhead: competitors.filter(c => c.shareOfVoice > yourBrand.shareOfVoice).length,
        competitorsBehind: competitors.filter(c => c.shareOfVoice < yourBrand.shareOfVoice).length,
        avgGap: (competitors.reduce((sum, c) => sum + c.shareOfVoice, 0) / competitors.length - yourBrand.shareOfVoice).toFixed(2),
      },
    };
  }
  ```

  ```python Python theme={null}
  from typing import List, Optional


  def get_competitive_landscape(client, brand_id: str, period: int = 30) -> dict:
      """Analyze competitive positioning and gaps."""
      data = client.get_competitors(brand_id, period=period, limit=20, sort='shareOfVoice')

      your_brand = next((c for c in data['competitors'] if c['relationship'] == 'SELF'), None)
      competitors = [c for c in data['competitors'] if c['relationship'] != 'SELF']

      if not your_brand:
          raise ValueError('Your brand not found in competitor data')

      your_sov = your_brand['shareOfVoice']

      return {
          'your_position': {
              'name': your_brand['name'],
              'share_of_voice': your_sov,
              'mentions': your_brand['totalMentions'],
              'avg_position': your_brand['avgPosition'],
              'sentiment': your_brand['avgSentiment'],
              'rank': next(i for i, c in enumerate(data['competitors']) if c['id'] == your_brand['id']) + 1,
          },
          'competitors': [
              {
                  'id': c['id'],
                  'name': c['name'],
                  'share_of_voice': c['shareOfVoice'],
                  'mentions': c['totalMentions'],
                  'avg_position': c['avgPosition'],
                  'sentiment': c['avgSentiment'],
                  'gap': round(c['shareOfVoice'] - your_sov, 2),
                  'status': 'ahead' if c['shareOfVoice'] > your_sov else 'behind',
              }
              for c in competitors
          ],
          'summary': {
              'total_competitors': len(competitors),
              'competitors_ahead': sum(1 for c in competitors if c['shareOfVoice'] > your_sov),
              'competitors_behind': sum(1 for c in competitors if c['shareOfVoice'] < your_sov),
              'avg_gap': round(sum(c['shareOfVoice'] for c in competitors) / len(competitors) - your_sov, 2) if competitors else 0,
          },
      }
  ```
</CodeGroup>

***

## Track Competitor Evolution

Monitor how a specific competitor's metrics change over time.

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function trackCompetitorEvolution(client, brandId, competitorId, period = 30) {
    const evolution = await client.getCompetitorEvolution(brandId, competitorId, { period });

    const dataPoints = evolution.evolution;
    if (dataPoints.length < 2) {
      return { trend: 'insufficient_data', dataPoints };
    }

    const first = dataPoints[0];
    const last = dataPoints[dataPoints.length - 1];

    const sovChange = last.shareOfVoice - first.shareOfVoice;
    const mentionChange = last.mentions - first.mentions;

    return {
      competitor: evolution.competitor,
      period: { start: first.date, end: last.date },
      metrics: {
        sovStart: first.shareOfVoice,
        sovEnd: last.shareOfVoice,
        sovChange: sovChange.toFixed(2),
        sovTrend: sovChange > 0.5 ? 'growing' : sovChange < -0.5 ? 'declining' : 'stable',
        mentionStart: first.mentions,
        mentionEnd: last.mentions,
        mentionChange,
      },
      dataPoints,
    };
  }
  ```

  ```python Python theme={null}
  def track_competitor_evolution(client, brand_id: str, competitor_id: str, period: int = 30) -> dict:
      """Track competitor metrics over time."""
      evolution = client.get_competitor_evolution(brand_id, competitor_id, period=period)

      data_points = evolution['evolution']
      if len(data_points) < 2:
          return {'trend': 'insufficient_data', 'data_points': data_points}

      first = data_points[0]
      last = data_points[-1]

      sov_change = last['shareOfVoice'] - first['shareOfVoice']
      mention_change = last['mentions'] - first['mentions']

      def get_trend(change: float) -> str:
          if change > 0.5:
              return 'growing'
          if change < -0.5:
              return 'declining'
          return 'stable'

      return {
          'competitor': evolution['competitor'],
          'period': {'start': first['date'], 'end': last['date']},
          'metrics': {
              'sov_start': first['shareOfVoice'],
              'sov_end': last['shareOfVoice'],
              'sov_change': round(sov_change, 2),
              'sov_trend': get_trend(sov_change),
              'mention_start': first['mentions'],
              'mention_end': last['mentions'],
              'mention_change': mention_change,
          },
          'data_points': data_points,
      }
  ```
</CodeGroup>

***

## Usage

<CodeGroup>
  ```javascript JavaScript theme={null}
  const client = new QwairyClient(process.env.QWAIRY_API_TOKEN);

  // Get landscape
  const landscape = await getCompetitiveLandscape(client, 'your-brand-id', 30);

  console.log(`\nYour Position: #${landscape.yourPosition.rank}`);
  console.log(`Share of Voice: ${landscape.yourPosition.shareOfVoice}%`);
  console.log(`\nCompetitors ahead: ${landscape.summary.competitorsAhead}`);
  console.log(`Competitors behind: ${landscape.summary.competitorsBehind}`);

  console.log('\nCompetitor Ranking:');
  console.log('─'.repeat(60));

  for (const c of landscape.competitors.slice(0, 5)) {
    const indicator = c.status === 'ahead' ? '↑' : '↓';
    console.log(`${c.name.padEnd(25)} ${c.shareOfVoice.toFixed(1)}% SOV  ${indicator} ${Math.abs(c.gap)}% gap`);
  }

  // Track top competitor
  const topCompetitor = landscape.competitors[0];
  if (topCompetitor) {
    const evolution = await trackCompetitorEvolution(client, 'your-brand-id', topCompetitor.id, 30);
    console.log(`\n${topCompetitor.name} trend: ${evolution.metrics.sovTrend} (${evolution.metrics.sovChange}%)`);
  }
  ```

  ```python Python theme={null}
  client = QwairyClient()

  # Get landscape
  landscape = get_competitive_landscape(client, 'your-brand-id', period=30)

  print(f"\nYour Position: #{landscape['your_position']['rank']}")
  print(f"Share of Voice: {landscape['your_position']['share_of_voice']}%")
  print(f"\nCompetitors ahead: {landscape['summary']['competitors_ahead']}")
  print(f"Competitors behind: {landscape['summary']['competitors_behind']}")

  print('\nCompetitor Ranking:')
  print('─' * 60)

  for c in landscape['competitors'][:5]:
      indicator = '↑' if c['status'] == 'ahead' else '↓'
      print(f"{c['name']:<25} {c['share_of_voice']:.1f}% SOV  {indicator} {abs(c['gap'])}% gap")

  # Track top competitor
  if landscape['competitors']:
      top = landscape['competitors'][0]
      evolution = track_competitor_evolution(client, 'your-brand-id', top['id'], period=30)
      print(f"\n{top['name']} trend: {evolution['metrics']['sov_trend']} ({evolution['metrics']['sov_change']}%)")
  ```
</CodeGroup>

***

## Example Output

**Console:**

```
Your Position: #3
Share of Voice: 8.13%

Competitors ahead: 2
Competitors behind: 7

Competitor Ranking:
────────────────────────────────────────────────────────────
Competitor A              12.5% SOV  ↑ 4.37% gap
Competitor B              9.8% SOV   ↑ 1.67% gap
Competitor C              6.2% SOV   ↓ 1.93% gap
Competitor D              5.1% SOV   ↓ 3.03% gap
Competitor E              4.8% SOV   ↓ 3.33% gap

Competitor A trend: stable (+0.3%)
```

**JSON:**

```json theme={null}
{
  "yourPosition": {
    "name": "My Brand",
    "shareOfVoice": 8.13,
    "mentions": 104,
    "avgPosition": 2.1,
    "sentiment": 78.1,
    "rank": 3
  },
  "competitors": [
    {
      "id": "comp1",
      "name": "Competitor A",
      "shareOfVoice": 12.5,
      "mentions": 156,
      "avgPosition": 1.8,
      "sentiment": 72.3,
      "gap": "4.37",
      "status": "ahead"
    }
  ],
  "summary": {
    "totalCompetitors": 9,
    "competitorsAhead": 2,
    "competitorsBehind": 7,
    "avgGap": "-1.23"
  }
}
```

***

## Key Metrics

| Metric        | Description                  | Action                           |
| ------------- | ---------------------------- | -------------------------------- |
| `gap`         | Difference in Share of Voice | Positive = competitor ahead      |
| `avgPosition` | Average rank in AI responses | Lower = better (1 is first)      |
| `status`      | Relative position            | `ahead` or `behind` your brand   |
| `sovTrend`    | Direction over time          | `growing`, `declining`, `stable` |

***

## Next Steps

* Build a [custom dashboard](/developers/guides/custom-dashboard) to visualize these insights
* Set up [weekly reports](/developers/guides/weekly-reports) to track changes
* [Export data](/developers/guides/data-export) for deeper analysis in BI tools
