← Back to DevBytes

Building a Competitor Monitoring Agent with LangChain: Complete Guide

Introduction: What Is a Competitor Monitoring Agent?

A Competitor Monitoring Agent is an autonomous AI-powered system that continuously tracks, analyzes, and reports on your competitors' digital footprint. Built on LangChain, it combines large language models (LLMs) with specialized tools — web scrapers, search APIs, news aggregators, and social media monitors — to create an intelligent watchtower that never sleeps.

Unlike traditional competitive intelligence dashboards that simply aggregate data, a LangChain-powered agent actively reasons about what it finds. It connects dots between disparate signals, interprets the strategic implications of a competitor's pricing change, identifies patterns in product launches, and delivers actionable insights in natural language — exactly the way a skilled market analyst would, but at machine scale and speed.

In this comprehensive guide, you'll build a fully functional competitor monitoring agent from scratch. You'll learn how to set up the LangChain environment, create specialized monitoring tools, wire up an agent with reasoning capabilities, implement scheduled monitoring pipelines, and apply production-grade best practices. Every code example is complete and ready to run.

Why Competitor Monitoring Matters for Modern Businesses

Competitive intelligence has evolved from a periodic manual effort into a continuous strategic necessity. Here's why an automated agent approach is transformative:

For product managers, founders, marketers, and strategy teams, a competitor monitoring agent is no longer a luxury — it's a competitive necessity in fast-moving markets.

Setting Up Your LangChain Environment

Before building the agent, let's set up a complete development environment. We'll need LangChain itself, along with supporting libraries for web scraping, search, scheduling, and embeddings.

Installing Required Dependencies

# Core LangChain packages
pip install langchain langchain-openai langchain-community

# Web scraping and HTML parsing
pip install httpx beautifulsoup4 lxml selenium-wire

# Search APIs
pip install google-search-results serpapi google-search-results

# Vector store and embeddings for long-term memory
pip install chromadb sentence-transformers

# Scheduling for production monitoring
pip install celery redis schedule

# Optional: browser automation for JavaScript-heavy sites
pip install playwright
playwright install chromium

API Keys and Environment Configuration

Create a .env file to store your API keys securely. At minimum, you'll need an OpenAI API key for the LLM and optionally a SerpAPI key for web search.

# .env file
OPENAI_API_KEY=sk-your-openai-api-key-here
SERPAPI_API_KEY=your-serpapi-key-here
# Optional: for direct Google Search access
GOOGLE_API_KEY=your-google-api-key
GOOGLE_CSE_ID=your-custom-search-engine-id

Load these in your Python application:

# config.py
import os
from dotenv import load_dotenv

load_dotenv()

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
SERPAPI_API_KEY = os.getenv("SERPAPI_API_KEY")
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
GOOGLE_CSE_ID = os.getenv("GOOGLE_CSE_ID")

# Model configuration
LLM_MODEL = "gpt-4-turbo"  # or "gpt-3.5-turbo" for cost savings
TEMPERATURE = 0.1  # low temperature for factual consistency

Building the Core Competitor Monitoring Agent

Now we'll build the agent step by step. The architecture follows LangChain's agent pattern: we define tools (what the agent can do), a system prompt (how it should think), and an agent executor that orchestrates reasoning and tool use.

Step 1: Define Custom Monitoring Tools

Tools are the agent's hands. Each tool wraps a specific capability — web search, page scraping, content extraction — into a function the LLM can invoke. Let's build a comprehensive toolset.

# tools/competitor_tools.py
import json
import httpx
from bs4 import BeautifulSoup
from typing import List, Optional, Dict
from langchain.tools import tool
from langchain_community.tools import GoogleSearchResults
from datetime import datetime


# --- Tool 1: Web Search for Competitor Mentions ---
@tool
def search_competitor_news(query: str) -> str:
    """
    Search the web for recent news, announcements, or mentions about a competitor.
    Input: A search query like "Acme Corp latest product launch 2024"
    Returns: Structured results with titles, snippets, and URLs from the last 30 days.
    """
    search_tool = GoogleSearchResults(
        api_key=os.getenv("SERPAPI_API_KEY"),
        params={
            "q": query,
            "tbs": "qdr:m",  # last month
            "num": 10,
            "hl": "en",
        }
    )
    results = search_tool.run(query)
    
    # Parse and structure results
    parsed = []
    for item in results.get("organic_results", [])[:10]:
        parsed.append({
            "title": item.get("title"),
            "snippet": item.get("snippet"),
            "url": item.get("link"),
            "date": item.get("date", "Unknown date")
        })
    return json.dumps(parsed, indent=2)


# --- Tool 2: Scrape a Specific Competitor Page ---
@tool
def scrape_competitor_page(url: str) -> str:
    """
    Scrape and extract the full text content from a competitor's web page.
    Input: A complete URL like 'https://competitor.com/pricing'
    Returns: The cleaned text content of the page, stripped of HTML tags and scripts.
    Use this to check pricing changes, new features, or messaging updates.
    """
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 (KHTML, like Gecko) "
                      "Chrome/120.0.0.0 Safari/537.36"
    }
    
    try:
        response = httpx.get(url, headers=headers, timeout=15, follow_redirects=True)
        response.raise_for_status()
        soup = BeautifulSoup(response.text, "lxml")
        
        # Remove script, style, and nav elements
        for tag in soup(["script", "style", "nav", "footer", "header"]):
            tag.decompose()
        
        # Extract text from main content areas
        main_content = soup.find("main") or soup.find("article") or soup.body
        if main_content:
            text = main_content.get_text(separator="\n", strip=True)
        else:
            text = soup.get_text(separator="\n", strip=True)
        
        # Clean up excessive whitespace
        lines = [line.strip() for line in text.split("\n") if line.strip()]
        cleaned_text = "\n".join(lines[:200])  # limit to 200 lines
        
        return f"URL: {url}\nTimestamp: {datetime.now().isoformat()}\n\nContent:\n{cleaned_text}"
    
    except Exception as e:
        return f"Error scraping {url}: {str(e)}"


# --- Tool 3: Check Specific Page Elements ---
@tool
def check_page_element(url: str, css_selector: str) -> str:
    """
    Extract specific elements from a competitor page using CSS selectors.
    Input: URL and CSS selector like 'https://competitor.com/pricing' and '.price-tier'
    Returns: The text content of matching elements.
    Use this to monitor specific pricing tables, feature lists, or call-to-action buttons.
    """
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
    }
    
    try:
        response = httpx.get(url, headers=headers, timeout=15, follow_redirects=True)
        response.raise_for_status()
        soup = BeautifulSoup(response.text, "lxml")
        
        elements = soup.select(css_selector)
        if not elements:
            return f"No elements found matching selector: {css_selector}"
        
        results = []
        for i, el in enumerate(elements[:20], 1):
            text = el.get_text(strip=True)
            if text:
                results.append(f"Element {i}: {text}")
        
        return "\n".join(results) if results else "Elements found but contained no text"
    
    except Exception as e:
        return f"Error checking element at {url}: {str(e)}"


# --- Tool 4: Compare Two Pages for Changes ---
@tool
def diff_competitor_pages(url: str, previous_content_hash: str) -> str:
    """
    Check if a competitor page has changed since last observation.
    Input: URL and a SHA256 hash of previously observed content.
    Returns: A detailed diff summary or confirmation that nothing changed.
    """
    import hashlib
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
    }
    
    try:
        response = httpx.get(url, headers=headers, timeout=15, follow_redirects=True)
        response.raise_for_status()
        
        # Clean and hash current content
        soup = BeautifulSoup(response.text, "lxml")
        for tag in soup(["script", "style"]):
            tag.decompose()
        current_text = soup.get_text(strip=True)
        current_hash = hashlib.sha256(current_text.encode()).hexdigest()
        
        if current_hash == previous_content_hash:
            return json.dumps({
                "changed": False,
                "message": "Page content is identical to previous observation.",
                "current_hash": current_hash,
                "timestamp": datetime.now().isoformat()
            })
        else:
            # Return first 3000 chars for LLM analysis
            return json.dumps({
                "changed": True,
                "message": "Page content has changed since last observation.",
                "current_hash": current_hash,
                "previous_hash": previous_content_hash,
                "current_content_preview": current_text[:3000],
                "timestamp": datetime.now().isoformat()
            })
    
    except Exception as e:
        return json.dumps({"error": str(e)})

Step 2: Create the Competitor Database for Memory

For effective monitoring over time, the agent needs memory — a way to remember what it observed yesterday so it can detect changes today. We'll use a lightweight ChromaDB vector store to persist competitor profiles and historical observations.

# memory/competitor_store.py
import chromadb
from chromadb.config import Settings
from langchain_openai import OpenAIEmbeddings
from datetime import datetime
import json


class CompetitorMemoryStore:
    """
    Persistent memory for competitor profiles and historical observations.
    Uses ChromaDB with OpenAI embeddings for semantic retrieval.
    """
    
    def __init__(self, persist_directory: str = "./competitor_db"):
        self.client = chromadb.Client(
            Settings(
                chroma_db_impl="duckdb+parquet",
                persist_directory=persist_directory,
                anonymized_telemetry=False
            )
        )
        self.embeddings = OpenAIEmbeddings(
            model="text-embedding-3-small",
            openai_api_key=os.getenv("OPENAI_API_KEY")
        )
        
        # Create or get collections
        self.profiles = self.client.get_or_create_collection(
            name="competitor_profiles",
            metadata={"description": "Core competitor information and profiles"}
        )
        self.observations = self.client.get_or_create_collection(
            name="competitor_observations",
            metadata={"description": "Historical monitoring observations"}
        )
    
    def store_profile(self, competitor_name: str, profile_data: Dict) -> str:
        """Store or update a competitor's profile."""
        doc_id = f"profile_{competitor_name.lower().replace(' ', '_')}"
        embedding = self.embeddings.embed_query(json.dumps(profile_data))
        
        self.profiles.upsert(
            ids=[doc_id],
            embeddings=[embedding],
            metadatas=[{
                "competitor_name": competitor_name,
                "updated_at": datetime.now().isoformat(),
                "data": json.dumps(profile_data)
            }],
            documents=[json.dumps(profile_data)]
        )
        return doc_id
    
    def store_observation(self, competitor_name: str, observation: str, metadata: Dict = None):
        """Record a new monitoring observation."""
        doc_id = f"obs_{competitor_name.lower().replace(' ', '_')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
        embedding = self.embeddings.embed_query(observation)
        
        meta = metadata or {}
        meta.update({
            "competitor_name": competitor_name,
            "timestamp": datetime.now().isoformat(),
            "observation_text": observation
        })
        
        self.observations.add(
            ids=[doc_id],
            embeddings=[embedding],
            metadatas=[meta],
            documents=[observation]
        )
        return doc_id
    
    def get_recent_observations(self, competitor_name: str, days: int = 7) -> List[str]:
        """Retrieve observations from the last N days for a competitor."""
        results = self.observations.get(
            where={"competitor_name": competitor_name},
            limit=20
        )
        observations = []
        for doc, meta in zip(results.get("documents", []), results.get("metadatas", [])):
            observations.append(f"[{meta.get('timestamp', 'Unknown')}] {doc}")
        return observations
    
    def get_profile(self, competitor_name: str) -> Optional[Dict]:
        """Retrieve a competitor's stored profile."""
        doc_id = f"profile_{competitor_name.lower().replace(' ', '_')}"
        results = self.profiles.get(ids=[doc_id])
        if results and results["metadatas"]:
            return json.loads(results["metadatas"][0].get("data", "{}"))
        return None

Step 3: Craft the System Prompt

The system prompt defines the agent's persona, reasoning framework, and operational boundaries. A well-crafted prompt transforms a general-purpose LLM into a specialized competitive intelligence analyst.

# prompts/system_prompt.py
COMPETITOR_ANALYST_PROMPT = """You are an elite Competitive Intelligence Analyst AI. Your mission is to monitor, analyze, 
and report on competitor activity with precision, depth, and strategic insight.

## Your Capabilities
You have access to these tools:
- search_competitor_news: Find recent news about competitors
- scrape_competitor_page: Extract full content from any competitor web page
- check_page_element: Extract specific elements (pricing, features, etc.) from pages
- diff_competitor_pages: Detect changes in competitor pages since last check

## Your Monitoring Targets
The following competitors are being tracked:
{competitor_list}

## Your Analysis Framework
For every observation, apply this structured analysis:

1. **FACTUAL OBSERVATION** - What exactly was observed? Quote specifics.
2. **STRATEGIC SIGNIFICANCE** - Why does this matter? Rate impact: LOW / MEDIUM / HIGH / CRITICAL
3. **COMPETITIVE RESPONSE** - What should we do? Suggest concrete actions.
4. **TREND CONNECTION** - Does this connect to previous observations or broader market trends?
5. **CONFIDENCE LEVEL** - How certain are you? (High/Medium/Low) and why.

## Output Format
Structure every report as:

---
**Date:** [current date]
**Competitor:** [name]
**Signal Type:** [Product Launch / Pricing Change / Marketing Shift / Hiring / Partnership / Other]

**Observation:**
[Detailed factual observation]

**Strategic Assessment:**
[Impact rating and rationale]

**Recommended Action:**
[Specific, actionable recommendations]

**Connections:**
[Links to previous observations or market context]

---

## Critical Rules
- Never fabricate information. If you cannot verify something, state your uncertainty clearly.
- Prioritize HIGH and CRITICAL signals for immediate attention.
- When you detect a pricing change, ALWAYS flag it as HIGH or CRITICAL.
- If a competitor launches a feature similar to our roadmap, flag it as CRITICAL.
- Maintain a professional, analytical tone. Avoid speculation without evidence.
- When in doubt, use scrape_competitor_page to verify before reporting.
"""

# Shorter prompt variant for quick scans
QUICK_SCAN_PROMPT = """You are a Competitive Intelligence Analyst. Quickly scan the provided content 
for any significant competitor signals. Focus on: pricing changes, new features, leadership changes, 
partnerships, funding news, and marketing shifts. Report only what's noteworthy with a 1-line impact assessment.

Content to analyze:
{content}"""

Step 4: Assemble the Agent Executor

Now we wire everything together. The agent executor manages the conversation loop: it receives a task, reasons about which tool to use, calls the tool, feeds the result back to the LLM, and repeats until it has a complete answer.

# agent/competitor_agent.py
import os
from typing import List, Dict
from datetime import datetime

from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.schema import SystemMessage, HumanMessage

from tools.competitor_tools import (
    search_competitor_news,
    scrape_competitor_page,
    check_page_element,
    diff_competitor_pages,
)
from memory.competitor_store import CompetitorMemoryStore
from prompts.system_prompt import COMPETITOR_ANALYST_PROMPT


class CompetitorMonitoringAgent:
    """
    Complete competitor monitoring agent with tools, memory, and reasoning.
    """
    
    def __init__(self, competitors: List[Dict], model: str = "gpt-4-turbo"):
        self.competitors = competitors
        self.memory = CompetitorMemoryStore()
        
        # Initialize LLM
        self.llm = ChatOpenAI(
            model=model,
            temperature=0.1,
            openai_api_key=os.getenv("OPENAI_API_KEY")
        )
        
        # Register tools
        self.tools = [
            search_competitor_news,
            scrape_competitor_page,
            check_page_element,
            diff_competitor_pages,
        ]
        
        # Build the agent
        self.agent = create_openai_tools_agent(
            llm=self.llm,
            tools=self.tools,
            prompt=self._build_prompt()
        )
        
        self.executor = AgentExecutor(
            agent=self.agent,
            tools=self.tools,
            verbose=True,
            max_iterations=8,
            max_execution_time=120,
            handle_parsing_errors=True,
            return_intermediate_steps=True,
        )
    
    def _build_prompt(self) -> ChatPromptTemplate:
        """Build the agent's prompt with competitor context."""
        competitor_str = "\n".join([
            f"- **{c['name']}** ({c.get('website', 'N/A')}): {c.get('description', '')}"
            for c in self.competitors
        ])
        
        system_content = COMPETITOR_ANALYST_PROMPT.format(
            competitor_list=competitor_str
        )
        
        return ChatPromptTemplate.from_messages([
            ("system", system_content),
            MessagesPlaceholder(variable_name="chat_history", optional=True),
            ("human", "{input}"),
            MessagesPlaceholder(variable_name="agent_scratchpad"),
        ])
    
    def run_monitoring_cycle(self, competitor_name: str, focus_areas: List[str] = None) -> Dict:
        """
        Run a complete monitoring cycle for a single competitor.
        
        Args:
            competitor_name: Name of the competitor to monitor
            focus_areas: Specific areas to focus on (pricing, products, hiring, etc.)
        
        Returns:
            Dict with full analysis report and metadata
        """
        focus = focus_areas or ["pricing", "new products", "leadership changes", 
                                 "partnerships", "marketing campaigns", "website changes"]
        
        # Build the monitoring task
        task = f"""
        Perform a comprehensive competitive intelligence scan on {competitor_name}.
        
        Focus specifically on these areas:
        {chr(10).join([f'- {area}' for area in focus])}
        
        Steps:
        1. First, use search_competitor_news to find recent mentions and news about {competitor_name}
        2. For their main website, use scrape_competitor_page to check their homepage, pricing page, 
           and any product pages you discover
        3. Use check_page_element to examine specific pricing tiers or feature lists
        4. If you have previous observations from memory, use diff_competitor_pages to check for changes
        
        Produce a structured analysis report following the framework in your system prompt.
        Flag any CRITICAL or HIGH impact signals immediately.
        """
        
        # Execute
        result = self.executor.invoke({
            "input": task
        })
        
        # Store the observation in memory
        self.memory.store_observation(
            competitor_name=competitor_name,
            observation=result.get("output", ""),
            metadata={
                "focus_areas": focus,
                "cycle_timestamp": datetime.now().isoformat()
            }
        )
        
        return {
            "competitor": competitor_name,
            "timestamp": datetime.now().isoformat(),
            "report": result.get("output"),
            "intermediate_steps": result.get("intermediate_steps", []),
            "tool_calls_count": len(result.get("intermediate_steps", []))
        }
    
    def run_full_monitoring(self) -> List[Dict]:
        """
        Run monitoring for ALL tracked competitors.
        Returns a list of reports.
        """
        reports = []
        for competitor in self.competitors:
            print(f"\n{'='*60}")
            print(f"Monitoring: {competitor['name']}")
            print(f"{'='*60}")
            
            report = self.run_monitoring_cycle(competitor['name'])
            reports.append(report)
        
        return reports
    
    def generate_daily_briefing(self) -> str:
        """Generate an executive briefing from today's observations."""
        all_obs = []
        for competitor in self.competitors:
            obs = self.memory.get_recent_observations(competitor['name'], days=1)
            all_obs.extend(obs)
        
        if not all_obs:
            return "No observations recorded today."
        
        briefing_prompt = f"""
        You are an executive briefing specialist. Synthesize the following competitive intelligence 
        observations into a concise executive briefing. Group signals by competitor and by strategic 
        impact level. Highlight the top 3 most critical signals that require immediate attention.
        
        Observations:
        {chr(10).join(all_obs)}
        
        Format:
        # Executive Daily Briefing - {datetime.now().strftime('%B %d, %Y')}
        
        ## Critical Signals (Immediate Action Required)
        [Top signals]
        
        ## Competitor-by-Competitor Summary
        [Organized by competitor]
        
        ## Trend Watch
        [Emerging patterns across competitors]
        """
        
        briefing_llm = ChatOpenAI(
            model="gpt-4-turbo",
            temperature=0.2,
            openai_api_key=os.getenv("OPENAI_API_KEY")
        )
        
        response = briefing_llm.invoke(briefing_prompt)
        return response.content

Step 5: Initialize and Run the Agent

Here's how to put everything together and execute your first monitoring run:

# main.py - Complete working example
import os
from dotenv import load_dotenv
from agent.competitor_agent import CompetitorMonitoringAgent

load_dotenv()

# Define your competitor watchlist
COMPETITORS = [
    {
        "name": "Stripe",
        "website": "https://stripe.com",
        "description": "Payment processing and financial infrastructure platform",
        "key_pages": ["/pricing", "/products", "/docs", "/blog"]
    },
    {
        "name": "Adyen",
        "website": "https://www.adyen.com",
        "description": "Global payments platform for enterprises",
        "key_pages": ["/pricing", "/products", "/resources"]
    },
    {
        "name": "Square",
        "website": "https://squareup.com",
        "description": "Payment solutions for small to large businesses",
        "key_pages": ["/pricing", "/products", "/news"]
    }
]

def main():
    """Run a complete competitor monitoring cycle."""
    
    print("šŸ” Initializing Competitor Monitoring Agent...")
    print(f"Tracking {len(COMPETITORS)} competitors\n")
    
    # Initialize the agent
    agent = CompetitorMonitoringAgent(
        competitors=COMPETITORS,
        model="gpt-4-turbo"  # Use gpt-3.5-turbo for lower cost
    )
    
    # Optional: Pre-populate competitor profiles
    for comp in COMPETITORS:
        agent.memory.store_profile(
            comp['name'],
            {
                "name": comp['name'],
                "website": comp['website'],
                "description": comp['description'],
                "key_pages": comp['key_pages'],
                "first_tracked": "2024-01-01"
            }
        )
    
    # Run a single competitor deep-dive
    print("šŸ“Š Running deep-dive on Stripe...")
    stripe_report = agent.run_monitoring_cycle(
        competitor_name="Stripe",
        focus_areas=["pricing changes", "new product features", "API updates", 
                     "partnership announcements", "leadership moves"]
    )
    
    print("\n" + "="*60)
    print("STRIPE MONITORING REPORT")
    print("="*60)
    print(stripe_report["report"])
    print(f"\nTool calls made: {stripe_report['tool_calls_count']}")
    
    # Run full monitoring on all competitors
    print("\n\nšŸ”„ Running full monitoring cycle on all competitors...")
    all_reports = agent.run_full_monitoring()
    
    # Generate executive briefing
    print("\n\nšŸ“‹ Generating Executive Daily Briefing...")
    briefing = agent.generate_daily_briefing()
    print(briefing)
    
    # Save reports to disk
    import json
    with open("monitoring_output.json", "w") as f:
        json.dump(all_reports, f, indent=2, default=str)
    
    print("\nāœ… Monitoring complete. Reports saved to monitoring_output.json")


if __name__ == "__main__":
    main()

Advanced Features and Customization

Once the core agent is running, you can extend it with advanced capabilities that transform it from a simple monitor into a strategic intelligence platform.

Adding Social Media Monitoring

Competitor activity on Twitter/X, LinkedIn, and other platforms often contains early signals. Here's a tool to track social presence:

# tools/social_monitor.py
import httpx
from langchain.tools import tool
from datetime import datetime, timedelta


@tool
def search_social_mentions(competitor_name: str, platform: str = "twitter") -> str:
    """
    Search for recent social media mentions of a competitor on specified platforms.
    Input: Competitor name and platform ('twitter', 'linkedin', 'reddit')
    Returns: Recent posts and discussions mentioning the competitor.
    """
    # Use a social search API (e.g., Social Searcher, or Twitter/X API via RapidAPI)
    # This example uses a generic search approach
    search_query = f"{competitor_name} site:{platform}.com (announcement OR launch OR new OR update)"
    
    # For production, use dedicated social media APIs
    # Example: Twitter API v2 via bearer token
    headers = {
        "Authorization": f"Bearer {os.getenv('TWITTER_BEARER_TOKEN')}",
        "Content-Type": "application/json"
    }
    
    # Simplified implementation - in production, use proper API endpoints
    # Return structured social data
    return f"Social mentions found for {competitor_name} on {platform}. [Implement with real API]"


@tool
def monitor_linkedin_jobs(competitor_name: str) -> str:
    """
    Monitor competitor's job postings on LinkedIn to detect hiring trends.
    Input: Competitor company name
    Returns: Recent job postings with titles, departments, and locations.
    Hiring spikes in specific departments often signal product expansion.
    """
    # In production, integrate with LinkedIn Jobs API or scraping
    # For now, use web search as proxy
    from tools.competitor_tools import search_competitor_news
    
    query = f"{competitor_name} hiring jobs careers new roles 2024"
    results = search_competitor_news(query)
    
    analysis_prompt = f"""
    Analyze these job-related search results for {competitor_name}.
    Identify: departments hiring, seniority levels, approximate hiring volume,
    and what product areas the hiring suggests they're investing in.
    
    Results: {results}
    """
    
    return analysis_prompt

Automated Pricing Intelligence

Pricing changes are among the most critical competitive signals. This specialized module does deep pricing analysis:

# tools/pricing_intel.py
from langchain.tools import tool
from typing import Dict
import json
import re


@tool
def extract_pricing_data(page_url: str) -> str:
    """
    Extract and structure pricing information from a competitor's pricing page.
    Input: URL of the competitor's pricing page
    Returns: Structured JSON with plan names, prices, features, and billing cycles.
    """
    from tools.competitor_tools import scrape_competitor_page
    
    page_content = scrape_competitor_page(page_url)
    
    # Use LLM to extract structured pricing data
    extraction_prompt = f"""
    Extract ALL pricing information from this page content. 
    Return a structured JSON object with this exact schema:
    {{
      "currency": "USD",
      "plans": [
        {{
          "name": "plan name",
          "price": numeric_price,
          "billing_cycle": "monthly/annual/one-time",
          "features": ["feature1", "feature2"],
          "limits": {{"users": null, "storage": "unlimited", ...}},
          "target_segment": "startup/enterprise/smb"
        }}
      ],
      "free_tier": true/false,
      "enterprise_custom_pricing": true/false,
      "last_updated": "date if visible"
    }}
    
    Page content:
    {page_content[:5000]}
    """
    
    llm = ChatOpenAI(model="gpt-4-turbo", temperature=0, 
                     openai_api_key=os.getenv("OPENAI_API_KEY"))
    response = llm.invoke(extraction_prompt)
    
    # Try to parse and validate JSON
    try:
        structured = json.loads(response.content)
        return json.dumps(structured, indent=2)
    except json.JSONDecodeError:
        return response.content


@tool
def compare_pricing_across_competitors(competitor_pages: Dict[str, str]) -> str:
    """
    Compare pricing across multiple competitors.
    Input: Dict mapping competitor names to their pricing page URLs
    Returns: Comparative pricing analysis with positioning insights.
    Example input: {{"Stripe": "https://stripe.com/pricing", "Adyen": "https://adyen.com/pricing"}}
    """
    all_pricing = {}
    for name, url in competitor_pages.items():
        pricing_data = extract_pricing_data(url)
        all_pricing[name] = pricing_data
    
    comparison_prompt = f"""
    Perform a detailed pricing comparison across these competitors:
    
    {json.dumps(all_pricing, indent=2)}
    
    Analyze:
    1. Price positioning (who's cheapest, most expensive)
    2. Feature differentiation at each tier
    3. Target segment alignment
    4. Pricing strategy signals (usage-based vs. tiered vs. flat-rate)
    5. Our competitive pricing recommendations
    
    Format as a structured comparison report.
    """
    
    llm = ChatOpenAI(model="gpt-4-turbo", temperature=0.2,
                     openai_api_key=os.getenv("OPENAI_API_KEY"))
    return llm.invoke(comparison_prompt).content

Setting Up Scheduled Production Monitoring

For production use, the agent needs to run on a schedule. Here's a robust scheduling setup using Celery with Redis, suitable for deployment:

# scheduler/monitoring_scheduler.py
from celery import Celery
from celery.schedules import crontab
from datetime import datetime
import json
import os

# Initialize Celery app
app = Celery(
    'competitor_monitoring',
    broker='redis://localhost:6379/0',
    backend='redis://localhost:6379/1'
)

app.conf.update(
    task_serializer='json',
    accept_content=['json'],
    result_serializer='json',
    timezone='UTC',
    enable_utc=True,
)

# Configure periodic tasks
app.conf.beat_schedule = {
    # Daily comprehensive monitoring at 6 AM
    'daily-full-monitoring': {
        'task': 'scheduler.monitoring_scheduler.run_full_monitoring',
        'schedule': crontab(hour=6, minute=0),
        'args':

— Ad —

Google AdSense will appear here after approval

← Back to all articles