> ## 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.

# Analyse concurrentielle

> Comparez les observations SELF et DIRECT, puis mesurez un concurrent sur un périmètre d’API constant.

Utilisez les endpoints concurrents pour comparer les mentions observées et la part de voix au sein d’un même ensemble de réponses suivies. Ce guide utilise le client réutilisable du [Démarrage rapide](/fr/developers/guides/index#api-client).

## Construire la comparaison

Demandez les relations SELF et DIRECT sur la même période. Ne traitez pas les autres types de relation comme des concurrents directs, sauf si votre analyse l’exige explicitement.

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

    const self = data.competitors.find(
      (item) => item.relationship === 'SELF'
    );
    if (!self) throw new Error('SELF brand is absent from the selected scope');

    const competitors = data.competitors
      .filter((item) => item.relationship === 'DIRECT')
      .map((item) => ({
        id: item.id,
        name: item.name,
        mentions: item.totalMentions,
        shareOfVoice: item.shareOfVoice,
        shareOfVoiceGap: Number(
          (item.shareOfVoice - self.shareOfVoice).toFixed(2)
        ),
        averagePosition: item.avgPosition,
        sentiment: item.avgSentiment,
      }));

    return {
      period,
      self: {
        id: self.id,
        name: self.name,
        mentions: self.totalMentions,
        shareOfVoice: self.shareOfVoice,
      },
      competitors,
    };
  }
  ```

  ```python Python theme={null}
  def build_competitive_landscape(client, brand_id: str, period: int = 30) -> dict:
      data = client.get_competitors(
          brand_id, period=period, limit=100,
          sort='shareOfVoice', order='desc',
      )

      self_brand = next(
          (item for item in data['competitors']
           if item['relationship'] == 'SELF'),
          None,
      )
      if self_brand is None:
          raise ValueError('SELF brand is absent from the selected scope')

      competitors = [
          {
              'id': item['id'],
              'name': item['name'],
              'mentions': item['totalMentions'],
              'share_of_voice': item['shareOfVoice'],
              'share_of_voice_gap': round(
                  item['shareOfVoice'] - self_brand['shareOfVoice'], 2
              ),
              'average_position': item['avgPosition'],
              'sentiment': item['avgSentiment'],
          }
          for item in data['competitors']
          if item['relationship'] == 'DIRECT'
      ]

      return {
          'period': period,
          'self': {
              'id': self_brand['id'],
              'name': self_brand['name'],
              'mentions': self_brand['totalMentions'],
              'share_of_voice': self_brand['shareOfVoice'],
          },
          'competitors': competitors,
      }
  ```
</CodeGroup>

Le wrapper Python n’expose pas le paramètre de requête `relationship`. Il filtre donc la réponse après récupération.

## Suivre un concurrent dans le temps

Indiquez l’écart observé sans lui attribuer un seuil de significativité universel. Si votre organisation utilise un seuil de matérialité, passez-le comme règle métier explicite et documentez son responsable.

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

    if (points.length < 2) {
      return { status: 'insufficient_data', points };
    }

    const first = points[0];
    const last = points.at(-1);
    const shareOfVoiceChange = Number(
      (last.shareOfVoice - first.shareOfVoice).toFixed(2)
    );

    return {
      status: 'observed',
      competitor: result.competitor,
      window: { start: first.date, end: last.date },
      shareOfVoice: {
        start: first.shareOfVoice,
        end: last.shareOfVoice,
        changePoints: shareOfVoiceChange,
        direction: shareOfVoiceChange > 0
          ? 'increased'
          : shareOfVoiceChange < 0
            ? 'decreased'
            : 'unchanged',
      },
      mentionChange: last.mentions - first.mentions,
      points,
    };
  }
  ```

  ```python Python theme={null}
  def compare_competitor_endpoints(
      client, brand_id: str, competitor_id: str, period: int = 30
  ) -> dict:
      result = client.get_competitor_evolution(
          brand_id, competitor_id, period=period
      )
      points = result['evolution']
      if len(points) < 2:
          return {'status': 'insufficient_data', 'points': points}

      first = points[0]
      last = points[-1]
      share_of_voice_change = round(
          last['shareOfVoice'] - first['shareOfVoice'], 2
      )
      direction = (
          'increased' if share_of_voice_change > 0
          else 'decreased' if share_of_voice_change < 0
          else 'unchanged'
      )

      return {
          'status': 'observed',
          'competitor': result['competitor'],
          'window': {'start': first['date'], 'end': last['date']},
          'share_of_voice': {
              'start': first['shareOfVoice'],
              'end': last['shareOfVoice'],
              'change_points': share_of_voice_change,
              'direction': direction,
          },
          'mention_change': last['mentions'] - first['mentions'],
          'points': points,
      }
  ```
</CodeGroup>

## Interpréter le résultat

* Un écart positif signifie que le concurrent a une part de voix plus élevée dans le périmètre d’API sélectionné. Ce n’est pas une part de marché.
* Le nombre de mentions, la position moyenne, le sentiment et les citations répondent à des questions différentes. Ne les réduisez pas à une explication causale unique.
* Ne comparez les évolutions que si les périmètres de prompts, de fournisseurs, de Topics, de Tags et de dates sont équivalents.
* Un lancement, une campagne ou une modification de contenu à une date proche est une hypothèse à étudier, pas une cause établie par cet endpoint.
* Examinez les réponses et les sources enregistrées avant de choisir une action.

## Pages associées

* [Lister les concurrents](/fr/developers/endpoints/competitors/list)
* [Obtenir un concurrent](/fr/developers/endpoints/competitors/get)
* [Évolution d’un concurrent](/fr/developers/endpoints/competitors/evolution)
* [Obtenir l’instantané de performance](/fr/developers/endpoints/performance)
* [Tableau de bord sur mesure](/fr/developers/guides/custom-dashboard)


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