AINode.jsAutomation

Competitor Research Automation Tool

Build an AI competitor research tool with Node.js that scrapes competitor websites, analyzes their messaging, content strategy, and pricing, then generates a structured competitive intelligence report.

TT
Emily Ross
5 min read
Competitor Research Automation Tool

Competitor Research Automation Tool

Keeping up with competitors manually takes hours every week. This tool scrapes multiple competitor websites simultaneously and uses GPT-4o to generate a structured competitive intelligence report — positioning, pricing, features, content strategy, and your differentiation opportunities.

This is Tool 11 of the Build 50 AI Automation Tools course.


What You'll Build

  • POST /research — provide competitor URLs, receive a full competitive intelligence report
  • Analyzes homepage, pricing, and about pages for each competitor
  • Generates a comparison matrix and differentiation recommendations

Setup

bash
mkdir competitor-research && cd competitor-research
npm init -y
npm install express axios cheerio openai dotenv p-limit
bash
# .env
OPENAI_API_KEY=sk-your-key-here
PORT=3000

Research Service

js
// src/services/researchService.js
import axios from 'axios';
import * as cheerio from 'cheerio';
import OpenAI from 'openai';
import pLimit from 'p-limit';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const limit = pLimit(3); // Max 3 concurrent requests

async function fetchPageText(url) {
  const { data } = await axios.get(url, {
    timeout: 15_000,
    headers: { 'User-Agent': 'Mozilla/5.0 (compatible; ResearchBot/1.0)' },
  });
  const $ = cheerio.load(data);
  $('script, style, nav, footer').remove();
  return $('body').text().replace(/\s+/g, ' ').slice(0, 8000);
}

async function fetchCompetitorData(baseUrl) {
  const urlObj = new URL(baseUrl);
  const pages = [
    { type: 'homepage', url: baseUrl },
    { type: 'about', url: `${urlObj.origin}/about` },
    { type: 'pricing', url: `${urlObj.origin}/pricing` },
  ];

  const pageData = await Promise.allSettled(
    pages.map(p => fetchPageText(p.url).then(text => ({ ...p, text })))
  );

  return pageData
    .filter(r => r.status === 'fulfilled')
    .map(r => r.value);
}

async function analyzeCompetitor(baseUrl, pages) {
  const combinedContent = pages.map(p => `[${p.type.toUpperCase()}]\n${p.text}`).join('\n\n---\n\n');

  const response = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [
      {
        role: 'system',
        content: `You are a strategic business analyst. Analyze this competitor's website content.
Return ONLY a JSON object — no markdown:
{
  "companyName": "string",
  "website": "${baseUrl}",
  "valueProposition": "1-2 sentence core value prop",
  "targetAudience": "string — who they're targeting",
  "mainFeatures": ["top 5-8 features/capabilities"],
  "pricing": {
    "model": "freemium | subscription | usage-based | one-time | contact-us | unknown",
    "tiers": [{"name": "string", "price": "string", "highlights": ["string"]}],
    "notes": "string"
  },
  "messaging": {
    "primaryTagline": "string",
    "keyBenefits": ["top selling points they emphasize"],
    "toneOfVoice": "professional | casual | technical | enterprise | startup"
  },
  "contentStrategy": {
    "blogTopics": ["main topics if blog found"],
    "contentFrequency": "string or null"
  },
  "trustSignals": ["customer logos mentioned, testimonials, awards, certifications"],
  "technicalIndicators": ["any tech stack clues — e.g. 'Built with React', 'Powered by AWS'"],
  "weaknesses": ["apparent gaps or weaknesses you can identify"],
  "strengths": ["clear competitive strengths"]
}`,
      },
      { role: 'user', content: combinedContent },
    ],
    temperature: 0.3,
    response_format: { type: 'json_object' },
  });

  return JSON.parse(response.choices[0].message.content);
}

async function synthesizeReport(yourProduct, competitorAnalyses) {
  const competitorSummaries = competitorAnalyses.map(c =>
    `${c.companyName}: ${c.valueProposition} | Features: ${c.mainFeatures.slice(0, 3).join(', ')} | Pricing: ${c.pricing.model}`
  ).join('\n');

  const response = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [
      {
        role: 'system',
        content: `You are a strategic consultant. Synthesize competitor data into actionable insights.
Return ONLY a JSON object:
{
  "marketLandscape": "2-3 sentence overview of the competitive landscape",
  "yourDifferentiators": ["unique angles your product should emphasize given these competitors"],
  "marketGaps": ["opportunities none of the competitors are addressing"],
  "positioningRecommendation": "string — how to position against this competitive set",
  "battlecards": [
    {
      "competitor": "string",
      "keyStrengths": ["string"],
      "vulnerabilities": ["string"],
      "talkingPoints": ["what to say when competing against this company"]
    }
  ],
  "priorityActions": ["top 3 things to do based on this competitive analysis"]
}`,
      },
      {
        role: 'user',
        content: `Your product: ${yourProduct || 'Not specified'}\n\nCompetitors:\n${competitorSummaries}`,
      },
    ],
    temperature: 0.4,
    response_format: { type: 'json_object' },
  });

  return JSON.parse(response.choices[0].message.content);
}

export async function researchCompetitors(competitorUrls, yourProduct = '') {
  const analyses = await Promise.all(
    competitorUrls.map(url => limit(async () => {
      const pages = await fetchCompetitorData(url);
      return analyzeCompetitor(url, pages);
    }))
  );

  const report = await synthesizeReport(yourProduct, analyses);

  return {
    generatedAt: new Date().toISOString(),
    competitorCount: analyses.length,
    competitors: analyses,
    strategicReport: report,
  };
}

Server

js
// src/server.js
import 'dotenv/config';
import express from 'express';
import { researchCompetitors } from './services/researchService.js';

const app = express();
app.use(express.json());

app.post('/research', async (req, res, next) => {
  try {
    const { competitors, yourProduct } = req.body;
    if (!competitors?.length) return res.status(400).json({ error: 'competitors array required' });
    const report = await researchCompetitors(competitors, yourProduct);
    res.json({ success: true, report });
  } catch (err) { next(err); }
});

app.use((err, _req, res, _next) => res.status(500).json({ error: err.message }));
app.listen(process.env.PORT ?? 3000, () => console.log('Competitor Research running'));

Testing

bash
curl -X POST http://localhost:3000/research \
  -H "Content-Type: application/json" \
  -d '{
    "competitors": [
      "https://competitor1.com",
      "https://competitor2.com",
      "https://competitor3.com"
    ],
    "yourProduct": "AI-powered project management tool for remote engineering teams"
  }'

Build 50 AI Automation Tools — Tool 11 of 50

Competitive research is live. Continue to Phase 3 with Tool 12: AI Email Reply Generator.


    Summary

    • p-limit controls concurrency — scrapes multiple competitors in parallel without overwhelming servers
    • Multi-page scraping (homepage, about, pricing) gives a comprehensive picture of each competitor
    • Two-stage AI analysis — individual competitor analysis + strategic synthesis = actionable report
    • Battlecards give sales teams specific talking points for each competitor
    • Schedule weekly runs and store results in a database to track competitor changes over time

    Continue to Tool 12: AI Email Reply Generator →