Want to know what tech stack your competitors use, where their servers are located, and what their site looks like — all from a single script? Let's build it.
We'll combine four free APIs to create a competitive intelligence tool that runs from the command line:
- Web Scraper — extract meta tags, headings, and links
- Screenshots — capture visual snapshots
- DNS Lookup — find hosting provider and infrastructure
- IP Geolocation — locate their servers
Get a Free API Key
All four APIs use the same key. Grab one (200 free credits, no credit card):
curl -X POST "https://api.frostbyte.world/api/keys/create"
Save the key from the response.
The Full Script
Create competitor-analysis.js:
const API_KEY = process.env.FROSTBYTE_KEY;
const BASE = 'https://api.frostbyte.world';
async function analyzeCompetitor(url) {
const domain = new URL(url).hostname;
console.log(`\n🔍 Analyzing ${domain}...\n`);
// Run all API calls in parallel
const [scrape, screenshot, dns, geo] = await Promise.all([
fetch(`${BASE}/api/scraper/scrape?url=${encodeURIComponent(url)}&format=json`, {
headers: { 'x-api-key': API_KEY }
}).then(r => r.json()),
fetch(`${BASE}/api/screenshot?url=${encodeURIComponent(url)}&width=1280&height=800`, {
headers: { 'x-api-key': API_KEY }
}).then(r => r.json()),
fetch(`${BASE}/api/dns/lookup?domain=${domain}&type=A`, {
headers: { 'x-api-key': API_KEY }
}).then(r => r.json()),
// We'll get geo data after DNS resolves
null
]);
// Get server IP and geolocate it
const serverIp = dns?.records?.[0]?.value;
let geoData = null;
if (serverIp) {
const geoRes = await fetch(`${BASE}/api/geo?ip=${serverIp}`, {
headers: { 'x-api-key': API_KEY }
});
geoData = await geoRes.json();
}
// Extract tech signals from scraped content
const techStack = detectTechStack(scrape);
return {
domain,
title: scrape?.title || 'N/A',
description: scrape?.meta?.description || 'N/A',
techStack,
server: {
ip: serverIp,
location: geoData ? `${geoData.city}, ${geoData.country}` : 'Unknown',
isp: geoData?.isp || 'Unknown',
org: geoData?.org || 'Unknown',
},
screenshot: screenshot?.screenshot_url || null,
links: {
internal: scrape?.links?.filter(l => l.includes(domain)).length || 0,
external: scrape?.links?.filter(l => !l.includes(domain)).length || 0,
}
};
}
function detectTechStack(scrapeData) {
const html = JSON.stringify(scrapeData).toLowerCase();
const techs = [];
const signatures = {
'React': ['react', 'reactdom', '__next', '_next/static'],
'Next.js': ['_next/', '__next', 'next/image'],
'Vue.js': ['vue.js', 'vuejs', '__vue'],
'Angular': ['ng-version', 'angular'],
'Svelte': ['svelte', '__svelte'],
'Tailwind CSS': ['tailwind', 'tw-'],
'Bootstrap': ['bootstrap'],
'WordPress': ['wp-content', 'wordpress'],
'Shopify': ['shopify', 'cdn.shopify'],
'Vercel': ['vercel', '_vercel'],
'Cloudflare': ['cloudflare', 'cf-ray'],
'Google Analytics': ['google-analytics', 'gtag', 'ga.js'],
'Google Tag Manager': ['googletagmanager', 'gtm.js'],
'Stripe': ['stripe.com', 'stripe.js'],
'Intercom': ['intercom', 'intercomcdn'],
'HubSpot': ['hubspot', 'hs-scripts'],
'Segment': ['segment.com', 'analytics.js'],
'Sentry': ['sentry.io', 'sentry'],
};
for (const [tech, patterns] of Object.entries(signatures)) {
if (patterns.some(p => html.includes(p))) {
techs.push(tech);
}
}
return techs;
}
// Compare multiple competitors
async function compareCompetitors(urls) {
console.log('='.repeat(60));
console.log(' COMPETITIVE ANALYSIS REPORT');
console.log('='.repeat(60));
const results = [];
for (const url of urls) {
try {
const result = await analyzeCompetitor(url);
results.push(result);
console.log(`\n📊 ${result.domain}`);
console.log(` Title: ${result.title}`);
console.log(` Tech: ${result.techStack.join(', ') || 'None detected'}`);
console.log(` Server: ${result.server.ip} (${result.server.location})`);
console.log(` Hosting: ${result.server.org}`);
console.log(` Links: ${result.links.internal} internal, ${result.links.external} external`);
if (result.screenshot) {
console.log(` Screenshot: ${result.screenshot}`);
}
} catch (err) {
console.error(` ❌ Error analyzing ${url}: ${err.message}`);
}
}
// Print comparison table
if (results.length > 1) {
console.log('\n' + '='.repeat(60));
console.log(' COMPARISON MATRIX');
console.log('='.repeat(60));
// Collect all unique techs
const allTechs = [...new Set(results.flatMap(r => r.techStack))];
console.log('\nTech Stack Overlap:');
for (const tech of allTechs) {
const users = results
.filter(r => r.techStack.includes(tech))
.map(r => r.domain);
console.log(` ${tech}: ${users.join(', ')}`);
}
}
return results;
}
// Run it
const competitors = process.argv.slice(2);
if (competitors.length === 0) {
console.log('Usage: node competitor-analysis.js https://site1.com https://site2.com');
process.exit(1);
}
compareCompetitors(competitors);
Run It
export FROSTBYTE_KEY="your-api-key"
node competitor-analysis.js https://stripe.com https://paddle.com https://lemonsqueezy.com
Example output:
============================================================
COMPETITIVE ANALYSIS REPORT
============================================================
📊 stripe.com
Title: Stripe | Financial Infrastructure for the Internet
Tech: React, Next.js, Google Analytics, Stripe
Server: 52.54.140.218 (Ashburn, United States)
Hosting: Amazon Technologies Inc.
Links: 142 internal, 8 external
Screenshot: https://api.frostbyte.world/screenshots/abc123.png
📊 paddle.com
Title: Paddle | The complete payments platform
Tech: Next.js, Tailwind CSS, Google Tag Manager, HubSpot
Server: 76.76.21.21 (San Francisco, United States)
Hosting: Vercel Inc
Links: 87 internal, 12 external
📊 lemonsqueezy.com
Title: Lemon Squeezy | Payments, tax & subscriptions
Tech: Vue.js, Tailwind CSS, Google Analytics, Stripe
Server: 172.67.182.31 (San Francisco, United States)
Hosting: Cloudflare Inc
Links: 64 internal, 5 external
============================================================
COMPARISON MATRIX
============================================================
Tech Stack Overlap:
React: stripe.com
Next.js: stripe.com, paddle.com
Vue.js: lemonsqueezy.com
Tailwind CSS: paddle.com, lemonsqueezy.com
Google Analytics: stripe.com, lemonsqueezy.com
Stripe: stripe.com, lemonsqueezy.com
Google Tag Manager: paddle.com
HubSpot: paddle.com
What This Tells You
From one command, you now know:
- Tech choices — Who uses React vs Vue? Who's on Next.js?
- Infrastructure — AWS vs Vercel vs Cloudflare. Where are servers located?
- Third-party services — Who uses HubSpot vs Intercom? Stripe vs custom payments?
- Content scale — Link counts hint at content strategy depth
- Visual design — Screenshots for side-by-side comparison
Extend It
Add more signals by combining with other endpoints:
// Check if they use CDN
const cdnCheck = await fetch(
`${BASE}/api/dns/lookup?domain=${domain}&type=CNAME`,
{ headers: { 'x-api-key': API_KEY } }
).then(r => r.json());
// Check email infrastructure (MX records)
const emailSetup = await fetch(
`${BASE}/api/dns/lookup?domain=${domain}&type=MX`,
{ headers: { 'x-api-key': API_KEY } }
).then(r => r.json());
console.log('Email provider:', emailSetup?.records?.[0]?.value);
// google.com → Google Workspace, outlook.com → Microsoft 365
Cost
Each competitor analysis uses 4 API credits (scrape + screenshot + DNS + geo). With 200 free credits, you can analyze 50 competitors at zero cost.
The full source code uses Node.js 18+ (native fetch). No external dependencies required.
Try the APIs: Frostbyte API | Get API Key
Top comments (0)