Skip to main content
Lesson 10 of 12 · Grok for Marketing & Competitive Intelligence

Automated Competitive Reports

Lesson 10 of 12 Updated July 30, 2026 Intermediate
On this page
  1. Automate competitive intelligence
  2. Architecture of a complete competitive report
  3. Build the reporting system
  4. Structure the report in usable JSON
  5. Compare periods to detect changes
  6. Schedule recurring execution
  7. Best practices for usable reports
  8. Key takeaways

Automate competitive intelligence

A one-off competitive report becomes obsolete within days. The real value lies in automation: regularly generated reports, structured identically, allowing you to compare periods and track your competitors’ strategic shifts.

This lesson shows you how to build an automated competitive reporting system that combines X data and web data.

Architecture of a complete competitive report

An effective marketing competitive report covers five axes, and their value comes from how they intersect: a product launch (axis 3) also shows up in publication volume (axis 1) and public sentiment (axis 4). This cross-referencing distinguishes intelligence from simple collection—a signal confirmed by two axes deserves attention, an isolated signal mostly deserves verification:

1. Social media activity

Publication volume, formats used, engagement, audience growth.

2. Content strategy

Topics covered, tone, positioning, observed editorial calendar.

3. Launches and announcements

New products, features, partnerships, events.

4. Public perception

Sentiment, complaints, praise, spontaneous comparisons with other brands.

5. Pricing and offer positioning

Price changes, promotions, packaging, special offers.

Build the reporting system

Competitive report class

from datetime import datetime, timedelta
import json

class RapportConcurrentiel:
    def __init__(self, client, marque_propre, concurrents):
        self.client = client
        self.marque = marque_propre
        self.concurrents = concurrents

    def collecter_donnees_x(self, handles, start, end):
        response = self.client.responses.create(
            model="grok-4.20-0309-reasoning",
            input=f"""Collect and analyze posts
            from these accounts from {start} to {end}.

            Provide for each account:
            - Estimated number of posts
            - Content types (text, image, video, thread)
            - Most engaging posts
            - Main themes covered
            - Observed tone and positioning
            - Detected announcements or launches""",
            tools=[{
                "type": "x_search",
                "allowed_x_handles": handles,
                "from_date": start,
                "to_date": end,
                "enable_image_understanding": True
            }]
        )
        return response.output_text

    def collecter_donnees_web(self, concurrent, start, end):
        response = self.client.responses.create(
            model="grok-4.20-0309-reasoning",
            input=f"""Search for recent news regarding
            {concurrent} between {start} and {end}.

            Focus on:
            - Press releases and news articles
            - Product or service updates
            - Leadership team changes
            - Fundraising or financial results
            - Strategic partnerships""",
            tools=[{
                "type": "web_search",
                "allowed_domains": [
                    "techcrunch.com", "lesechos.fr",
                    "usine-digitale.fr"
                ]
            }]
        )
        return response.output_text

Generate the compiled report

    def generer_rapport(self, periode_jours=30):
        end = datetime.now().strftime("%Y-%m-%d")
        start = (datetime.now() - timedelta(
            days=periode_jours)).strftime("%Y-%m-%d")

        sections = {}

        # Collect data for each competitor
        for concurrent in self.concurrents:
            handles = concurrent.get("handles", [])
            nom = concurrent["nom"]

            donnees_x = self.collecter_donnees_x(
                handles, start, end
            ) if handles else "No X data"

            donnees_web = self.collecter_donnees_web(
                nom, start, end
            )

            sections[nom] = {
                "x": donnees_x,
                "web": donnees_web
            }

        # Comparative summary
        rapport_final = self.client.responses.create(
            model="grok-4.20-0309-reasoning",
            input=f"""Compile this monthly competitive report.

            Our brand: {self.marque}
            Period: {start} to {end}

            DATA PER COMPETITOR:
            {json.dumps(sections, ensure_ascii=False, indent=2)}

            Report structure:
            1. EXECUTIVE SUMMARY (5 bullet points max)
            2. COMPARATIVE TABLE (activity, sentiment, innovation)
            3. ANALYSIS PER COMPETITOR (strengths, weaknesses, moves)
            4. IDENTIFIED THREATS (ranked by urgency)
            5. OPPORTUNITIES FOR {self.marque}
            6. STRATEGIC RECOMMENDATIONS (3-5 priority actions)"""
        ).output_text

        return rapport_final

Structure the report in usable JSON

To feed a dashboard or database, request a structured format:

    def rapport_json(self, periode_jours=30):
        end = datetime.now().strftime("%Y-%m-%d")
        start = (datetime.now() - timedelta(
            days=periode_jours)).strftime("%Y-%m-%d")

        response = self.client.responses.create(
            model="grok-4.20-0309-reasoning",
            input=f"""Generate a competitive report in JSON.

            Competitors: {json.dumps([c['nom'] for c in self.concurrents])}
            Period: {start} to {end}

            Expected format:
            {{
              "period": "{start} - {end}",
              "competitors": [
                {{
                  "name": "Competitor A",
                  "social_activity": {{
                    "post_volume": 45,
                    "average_engagement": "high",
                    "dominant_formats": ["image", "thread"]
                  }},
                  "public_sentiment": 3.8,
                  "innovations": ["description"],
                  "threats": ["description"],
                  "main_strength": "description",
                  "main_weakness": "description"
                }}
              ],
              "recommendations": ["action 1", "action 2"]
            }}""",
            tools=[
                {"type": "x_search", "from_date": start, "to_date": end},
                {"type": "web_search"}
            ]
        )
        return response.output_text

Compare periods to detect changes

The value of an automated system lies in temporal comparison:

def comparer_rapports(rapport_actuel, rapport_precedent):
    response = client.responses.create(
        model="grok-4.20-0309-reasoning",
        input=f"""Compare these two consecutive
        competitive reports and identify significant changes:

        PREVIOUS REPORT: {rapport_precedent}
        CURRENT REPORT: {rapport_actuel}

        Analysis:
        1. Which competitors changed strategy?
        2. What new threats appeared?
        3. What opportunities opened or closed?
        4. What trends are confirmed or reversing?
        5. Recommended immediate actions."""
    )
    return response.output_text

Schedule recurring execution

Integrate your report into a cron job or Python scheduler:

# Weekly execution
rapport = RapportConcurrentiel(
    client=client,
    marque_propre="Your Brand",
    concurrents=[
        {
            "nom": "Competitor A",
            "handles": ["competitor_a", "competitor_a_fr"]
        },
        {
            "nom": "Competitor B",
            "handles": ["competitor_b"]
        },
        {
            "nom": "Competitor C",
            "handles": ["competitor_c"]
        }
    ]
)

# Weekly report
resultat = rapport.generer_rapport(periode_jours=7)

# Archive the report
with open(f"reports/competitor_{datetime.now().strftime('%Y-%m-%d')}.md",
          "w") as f:
    f.write(resultat)

Best practices for usable reports

  • Consistency: always use the same structure to facilitate comparison
  • Prioritization: rank insights by business impact, not volume
  • Actionability: every section must lead to a recommendation
  • Distribution: adapt the format to the recipient (executive = summary, operational = detail)
  • Archiving: keep all reports for long-term trend analysis

Key takeaways

  • An automated competitive report covers 5 axes: social, content, launches, perception, pricing
  • Combine X Search and Web Search for a complete view of each competitor
  • Structure results in JSON to feed your dashboards
  • Comparison between periods reveals strategic changes
  • Every insight must lead to an actionable recommendation
  • Systematically archive your reports for long-term tracking