Back to Blog
January 30, 2024
Business Intelligence Team
3 min read
Business Strategy

Competitive Intelligence Dashboard: Monitor Your Competition with Zapserp

Build an automated competitive intelligence system to track competitor activities, product launches, marketing campaigns, and industry trends. Stay ahead of the competition with real-time insights.

competitive-intelligencebusiness-strategymarket-researchautomationdashboard

Competitive Intelligence Dashboard: Monitor Your Competition with Zapserp

Stay ahead of your competition by automatically monitoring their activities, product launches, marketing campaigns, and public communications. This guide shows you how to build a comprehensive competitive intelligence system that keeps you informed about market movements.

What We're Building

A smart competitive intelligence dashboard that:

  • Monitors competitor websites for changes and announcements
  • Tracks product launches and pricing updates
  • Analyzes marketing campaigns and content strategies
  • Monitors social media mentions and sentiment
  • Generates automated competitive analysis reports

Core Intelligence Engine

const { Zapserp } = require('zapserp')

class CompetitiveIntelligence {
  constructor(apiKey) {
    this.zapserp = new Zapserp({ apiKey })
    this.competitors = new Map()
    this.alertHistory = []
    this.trackingCategories = [
      'product_launches', 'pricing_changes', 'marketing_campaigns',
      'press_releases', 'partnerships', 'funding', 'hiring'
    ]
  }

  addCompetitor(name, domain, focusAreas = []) {
    this.competitors.set(name, {
      name,
      domain,
      focusAreas: focusAreas.length > 0 ? focusAreas : this.trackingCategories,
      lastUpdate: null,
      baseline: null
    })
  }

  async scanCompetitor(competitorName) {
    const competitor = this.competitors.get(competitorName)
    if (!competitor) throw new Error(`Competitor ${competitorName} not found`)

    const intelligence = {
      competitor: competitorName,
      timestamp: new Date().toISOString(),
      findings: {},
      alerts: []
    }

    // Scan each focus area
    for (const area of competitor.focusAreas) {
      try {
        const results = await this.scanFocusArea(competitor, area)
        intelligence.findings[area] = results
        
        // Check for significant changes that warrant alerts
        const alerts = this.analyzeForAlerts(competitor, area, results)
        intelligence.alerts.push(...alerts)
        
      } catch (error) {
        console.error(`Failed to scan ${area} for ${competitorName}:`, error)
        intelligence.findings[area] = { error: error.message }
      }
    }

    // Update competitor tracking data
    competitor.lastUpdate = intelligence.timestamp
    this.alertHistory.push(...intelligence.alerts)

    return intelligence
  }

  async scanFocusArea(competitor, area) {
    const searchQueries = this.getSearchQueries(competitor, area)
    const allFindings = []

    for (const query of searchQueries) {
      try {
        const searchResults = await this.zapserp.search({
          query,
          engines: ['google', 'bing'],
          limit: 10,
          language: 'en',
          country: 'us'
        })

        // Filter results to focus on relevant sources
        const relevantResults = this.filterRelevantSources(searchResults.results, area)
        
        if (relevantResults.length > 0) {
          const urls = relevantResults.slice(0, 5).map(result => result.url)
          const contentResults = await this.zapserp.readerBatch({ urls })

          contentResults.results.forEach(content => {
            if (content && content.content) {
              const analysis = this.analyzeContent(content, area, competitor)
              if (analysis.relevance > 0.5) {
                allFindings.push({
                  ...analysis,
                  url: content.url,
                  timestamp: new Date().toISOString(),
                  query
                })
              }
            }
          })
        }
      } catch (error) {
        console.error(`Search failed for ${area} query: ${query}`, error)
      }
    }

    return {
      area,
      totalFindings: allFindings.length,
      findings: allFindings.sort((a, b) => b.relevance - a.relevance),
      summary: this.generateSummary(allFindings, area)
    }
  }

  getSearchQueries(competitor, area) {
    const baseQueries = {
      product_launches: [
        `${competitor.name} new product launch 2024`,
        `${competitor.name} announces new product`,
        `${competitor.name} product release announcement`
      ],
      pricing_changes: [
        `${competitor.name} price increase decrease 2024`,
        `${competitor.name} pricing strategy changes`,
        `${competitor.name} costs more expensive cheaper`
      ],
      marketing_campaigns: [
        `${competitor.name} marketing campaign advertising`,
        `${competitor.name} commercial advertisement 2024`,
        `${competitor.name} brand campaign launch`
      ],
      press_releases: [
        `${competitor.name} press release announcement`,
        `${competitor.name} company news updates`,
        `${competitor.name} official statement`
      ],
      partnerships: [
        `${competitor.name} partnership collaboration`,
        `${competitor.name} alliance strategic partnership`,
        `${competitor.name} joint venture agreement`
      ],
      funding: [
        `${competitor.name} funding investment round`,
        `${competitor.name} raises capital series`,
        `${competitor.name} valuation investment`
      ],
      hiring: [
        `${competitor.name} hiring jobs careers`,
        `${competitor.name} new employees team expansion`,
        `${competitor.name} executive appointment CEO CTO`
      ]
    }

    return baseQueries[area] || []
  }

  filterRelevantSources(results, area) {
    const relevantSources = {
      product_launches: ['techcrunch.com', 'theverge.com', 'engadget.com', 'wired.com'],
      pricing_changes: ['bloomberg.com', 'reuters.com', 'wsj.com', 'forbes.com'],
      marketing_campaigns: ['adweek.com', 'marketingland.com', 'adage.com'],
      press_releases: ['prnewswire.com', 'businesswire.com', 'globenewswire.com'],
      partnerships: ['reuters.com', 'bloomberg.com', 'techcrunch.com'],
      funding: ['crunchbase.com', 'techcrunch.com', 'venturebeat.com'],
      hiring: ['linkedin.com', 'glassdoor.com', 'indeed.com']
    }

    const areaRelevantSources = relevantSources[area] || []
    
    return results.filter(result => {
      // Include results from relevant sources for this area
      if (areaRelevantSources.some(source => result.url.includes(source))) {
        return true
      }
      
      // Include results from competitor's own domain
      if (result.url.includes(this.competitors.get(result.competitor)?.domain)) {
        return true
      }
      
      // Include results with high relevance indicators
      return this.hasRelevanceIndicators(result.snippet, area)
    })
  }

  hasRelevanceIndicators(snippet, area) {
    const indicators = {
      product_launches: ['launch', 'announce', 'release', 'unveil', 'introduce'],
      pricing_changes: ['price', 'cost', 'pricing', 'expensive', 'cheaper', 'discount'],
      marketing_campaigns: ['campaign', 'advertising', 'marketing', 'brand', 'commercial'],
      press_releases: ['announces', 'statement', 'press release', 'official'],
      partnerships: ['partnership', 'collaborate', 'alliance', 'joint venture'],
      funding: ['funding', 'investment', 'raised', 'series', 'valuation'],
      hiring: ['hiring', 'jobs', 'careers', 'employees', 'team', 'executive']
    }

    const areaIndicators = indicators[area] || []
    const lowerSnippet = snippet.toLowerCase()
    
    return areaIndicators.some(indicator => lowerSnippet.includes(indicator))
  }

  analyzeContent(content, area, competitor) {
    const text = content.content.toLowerCase()
    const title = content.title?.toLowerCase() || ''
    
    // Calculate relevance score
    let relevance = 0
    
    // Competitor name mentions
    const competitorMentions = (text.match(new RegExp(competitor.name.toLowerCase(), 'g')) || []).length
    relevance += Math.min(competitorMentions * 0.2, 1)
    
    // Area-specific keywords
    const areaKeywords = this.getAreaKeywords(area)
    const keywordMatches = areaKeywords.filter(keyword => text.includes(keyword)).length
    relevance += Math.min(keywordMatches * 0.1, 0.5)
    
    // Title relevance bonus
    if (title.includes(competitor.name.toLowerCase())) relevance += 0.3
    
    // Recency bonus (content published within last 30 days)
    if (content.metadata?.publishedTime) {
      const publishedDate = new Date(content.metadata.publishedTime)
      const daysSincePublished = (Date.now() - publishedDate.getTime()) / (1000 * 60 * 60 * 24)
      if (daysSincePublished <= 30) relevance += 0.2
    }

    // Extract key insights
    const insights = this.extractInsights(content, area)
    
    return {
      title: content.title,
      summary: this.extractSummary(content.content),
      relevance: Math.min(relevance, 1),
      area,
      insights,
      publishedTime: content.metadata?.publishedTime,
      source: this.extractSource(content.url)
    }
  }

  getAreaKeywords(area) {
    const keywords = {
      product_launches: ['launch', 'release', 'announce', 'unveil', 'new product', 'features'],
      pricing_changes: ['price', 'pricing', 'cost', 'expensive', 'cheaper', 'discount', 'increase'],
      marketing_campaigns: ['campaign', 'advertising', 'marketing', 'brand', 'promotion'],
      press_releases: ['press release', 'announces', 'statement', 'news', 'update'],
      partnerships: ['partnership', 'collaboration', 'alliance', 'agreement', 'deal'],
      funding: ['funding', 'investment', 'capital', 'series', 'valuation', 'raised'],
      hiring: ['hiring', 'jobs', 'team', 'employees', 'recruit', 'executive', 'appointment']
    }
    
    return keywords[area] || []
  }

  extractInsights(content, area) {
    const insights = []
    const text = content.content
    
    // Extract specific insights based on area
    switch (area) {
      case 'product_launches':
        insights.push(...this.extractProductInsights(text))
        break
      case 'pricing_changes':
        insights.push(...this.extractPricingInsights(text))
        break
      case 'funding':
        insights.push(...this.extractFundingInsights(text))
        break
      // Add more specific extraction logic for other areas
    }
    
    return insights
  }

  extractProductInsights(text) {
    const insights = []
    
    // Look for product names and features
    const productPattern = /(?:new|latest|introducing)\s+([A-Z][A-Za-z\s]+)(?:product|solution|platform)/gi
    let match
    while ((match = productPattern.exec(text)) !== null) {
      insights.push({
        type: 'product_name',
        value: match[1].trim(),
        context: match[0]
      })
    }
    
    return insights
  }

  extractPricingInsights(text) {
    const insights = []
    
    // Look for price mentions
    const pricePattern = /\$(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)/g
    let match
    while ((match = pricePattern.exec(text)) !== null) {
      insights.push({
        type: 'price',
        value: parseFloat(match[1].replace(/,/g, '')),
        context: text.substring(match.index - 50, match.index + 50)
      })
    }
    
    return insights
  }

  extractFundingInsights(text) {
    const insights = []
    
    // Look for funding amounts
    const fundingPattern = /(?:raised|funding|investment).*?\$(\d+(?:\.\d+)?)\s*(million|billion)/gi
    let match
    while ((match = fundingPattern.exec(text)) !== null) {
      const amount = parseFloat(match[1])
      const multiplier = match[2].toLowerCase() === 'billion' ? 1000 : 1
      insights.push({
        type: 'funding_amount',
        value: amount * multiplier,
        unit: 'million',
        context: match[0]
      })
    }
    
    return insights
  }

  analyzeForAlerts(competitor, area, results) {
    const alerts = []
    
    // High relevance findings
    const highRelevanceFindings = results.findings.filter(f => f.relevance > 0.8)
    if (highRelevanceFindings.length > 0) {
      alerts.push({
        type: 'high_relevance_activity',
        competitor: competitor.name,
        area,
        message: `${highRelevanceFindings.length} high-relevance ${area} activities detected`,
        findings: highRelevanceFindings.slice(0, 3)
      })
    }
    
    // Recent significant news
    const recentFindings = results.findings.filter(f => {
      if (!f.publishedTime) return false
      const publishedDate = new Date(f.publishedTime)
      const hoursAgo = (Date.now() - publishedDate.getTime()) / (1000 * 60 * 60)
      return hoursAgo <= 24 // Within last 24 hours
    })
    
    if (recentFindings.length > 0) {
      alerts.push({
        type: 'recent_activity',
        competitor: competitor.name,
        area,
        message: `${recentFindings.length} recent ${area} activities in last 24 hours`,
        findings: recentFindings
      })
    }
    
    return alerts
  }

  generateSummary(findings, area) {
    if (findings.length === 0) return `No significant ${area} activity detected.`
    
    const avgRelevance = findings.reduce((sum, f) => sum + f.relevance, 0) / findings.length
    const recentCount = findings.filter(f => {
      if (!f.publishedTime) return false
      const publishedDate = new Date(f.publishedTime)
      const daysAgo = (Date.now() - publishedDate.getTime()) / (1000 * 60 * 60 * 24)
      return daysAgo <= 7
    }).length
    
    return `Found ${findings.length} relevant ${area} mentions (avg relevance: ${(avgRelevance * 100).toFixed(1)}%). ${recentCount} activities in the last week.`
  }

  extractSummary(content) {
    const sentences = content.split('.').filter(s => s.trim().length > 30)
    return sentences[0] ? sentences[0].trim() + '.' : content.substring(0, 150) + '...'
  }

  extractSource(url) {
    try {
      return new URL(url).hostname.replace('www.', '')
    } catch {
      return 'Unknown Source'
    }
  }

  // Generate competitive intelligence report
  async generateReport(competitors = null) {
    const targetCompetitors = competitors || Array.from(this.competitors.keys())
    const report = {
      timestamp: new Date().toISOString(),
      competitors: {},
      summary: {
        totalAlerts: 0,
        highActivityCompetitors: [],
        trendingAreas: []
      }
    }

    for (const competitorName of targetCompetitors) {
      const intelligence = await this.scanCompetitor(competitorName)
      report.competitors[competitorName] = intelligence
      report.summary.totalAlerts += intelligence.alerts.length
      
      if (intelligence.alerts.length > 2) {
        report.summary.highActivityCompetitors.push(competitorName)
      }
    }

    return report
  }
}

module.exports = CompetitiveIntelligence

Usage Examples

Basic Competitor Monitoring

const intel = new CompetitiveIntelligence('your-zapserp-api-key')

// Add competitors to monitor
intel.addCompetitor('OpenAI', 'openai.com', ['product_launches', 'partnerships', 'funding'])
intel.addCompetitor('Anthropic', 'anthropic.com', ['product_launches', 'hiring', 'funding'])

// Scan a specific competitor
const openaiIntel = await intel.scanCompetitor('OpenAI')

console.log(`Found ${openaiIntel.alerts.length} alerts for OpenAI`)
openaiIntel.alerts.forEach(alert => {
  console.log(`🚨 ${alert.type}: ${alert.message}`)
})

Automated Daily Reports

// Generate daily competitive intelligence report
const report = await intel.generateReport()

console.log(`📊 Daily Intelligence Report - ${new Date().toLocaleDateString()}`)
console.log(`Total Alerts: ${report.summary.totalAlerts}`)
console.log(`High Activity Competitors: ${report.summary.highActivityCompetitors.join(', ')}`)

Object.entries(report.competitors).forEach(([name, data]) => {
  console.log(`\n${name}:`)
  Object.entries(data.findings).forEach(([area, results]) => {
    console.log(`  ${area}: ${results.summary}`)
  })
})

Focus Area Analysis

// Deep dive into specific area for all competitors
const targetCompetitors = ['OpenAI', 'Anthropic', 'Cohere']

for (const competitor of targetCompetitors) {
  const productFindings = await intel.scanFocusArea(
    intel.competitors.get(competitor), 
    'product_launches'
  )
  
  console.log(`${competitor} Product Activity:`)
  console.log(productFindings.summary)
  
  productFindings.findings.slice(0, 3).forEach(finding => {
    console.log(`  • ${finding.title} (${(finding.relevance * 100).toFixed(1)}% relevant)`)
  })
}

Automated Monitoring Setup

// Set up automated monitoring every 8 hours
setInterval(async () => {
  try {
    const report = await intel.generateReport()
    
    // Send high-priority alerts immediately
    const urgentAlerts = []
    Object.values(report.competitors).forEach(competitor => {
      const urgent = competitor.alerts.filter(alert => 
        alert.type === 'recent_activity' || alert.type === 'high_relevance_activity'
      )
      urgentAlerts.push(...urgent)
    })
    
    if (urgentAlerts.length > 0) {
      console.log(`🚨 ${urgentAlerts.length} urgent competitive alerts detected`)
      // Here you would send notifications via email, Slack, etc.
    }
    
  } catch (error) {
    console.error('❌ Competitive intelligence scan failed:', error)
  }
}, 8 * 60 * 60 * 1000) // 8 hours

Best Practices

  1. Focus Areas: Start with 3-4 key areas most relevant to your business
  2. Alert Tuning: Adjust relevance thresholds based on signal quality
  3. Source Quality: Prioritize authoritative sources for each intelligence area
  4. Historical Tracking: Store findings over time to identify trends
  5. Action Items: Convert intelligence into actionable business insights

Conclusion

You now have a powerful competitive intelligence system that automatically monitors your competitors across multiple dimensions. This system helps you stay informed about market movements, identify opportunities, and respond quickly to competitive threats.

Ready to expand? Consider adding sentiment analysis, social media monitoring, or integration with business intelligence tools for deeper insights.

Found this helpful?

Share it with your network and help others discover great content.

Related Articles

Build an intelligent research assistant that finds academic papers, extracts key findings, and generates literature reviews automatically. Perfect for researchers, students, and academics.

3 min read
Education

Create an automated price tracking system to monitor competitor prices, track product availability, and send alerts when prices drop. Perfect for e-commerce businesses and deal hunters.

3 min read
E-commerce

Build a live stock market monitoring dashboard using Zapserp for real-time financial news and market analysis. Complete with React components and WebSocket updates.

4 min read
Financial Apps