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
- Focus Areas: Start with 3-4 key areas most relevant to your business
- Alert Tuning: Adjust relevance thresholds based on signal quality
- Source Quality: Prioritize authoritative sources for each intelligence area
- Historical Tracking: Store findings over time to identify trends
- 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.