I wanted to know what every competitor in my space was doing with their pricing page CTAs. Opening 50 tabs and reading each one would take an hour. I built a script that did it in 90 seconds.
The batch endpoint
SnapAPI's /v1/batch endpoint accepts a POST body with an array of URLs and an endpoint name. It runs that endpoint against all URLs in parallel and returns an array of results.
{
"endpoint": "analyze",
"urls": [
"https://stripe.com/pricing",
"https://notion.so/pricing",
"https://linear.app/pricing"
],
"api_key": "YOUR_KEY"
}
One POST. All results. Each URL counts as one API call against your quota — so a batch of 10 uses 10 calls.
The full script
// competitor-audit.js
// Batch-analyze competitor pricing pages and print a markdown table.
// Node.js 18+, no npm install needed.
const COMPETITORS = [
'https://stripe.com/pricing',
'https://notion.so/pricing',
'https://linear.app/pricing',
'https://vercel.com/pricing',
'https://render.com/pricing',
];
const API_KEY = process.env.SNAPAPI_KEY;
if (!API_KEY) { console.error('Set SNAPAPI_KEY. Free key at https://snapapi.tech/start'); process.exit(1); }
async function main() {
console.log(`Analyzing ${COMPETITORS.length} URLs in parallel...`);
const res = await fetch('https://api.snapapi.tech/v1/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ endpoint: 'analyze', urls: COMPETITORS, api_key: API_KEY }),
});
if (!res.ok) { console.error(`Batch failed: ${res.status}`); process.exit(1); }
const { results } = await res.json();
// Print markdown table
console.log('\n| URL | CTA Count | Top CTA | Word Count | Technologies |');
console.log('|-----|-----------|---------|------------|--------------|');
for (const r of results) {
if (r.status !== 'ok') { console.log(`| ${r.url} | ERROR | ${r.error} | — | — |`); continue; }
const ctas = Array.isArray(r.cta) ? r.cta : (r.primary_cta ? [r.primary_cta] : []);
const tech = (r.technologies || []).slice(0, 3).join(', ');
console.log(`| ${r.url} | ${ctas.length} | ${ctas[0] || '—'} | ${r.word_count ?? '—'} | ${tech} |`);
}
}
main().catch(err => { console.error(err.message); process.exit(1); });
Run it:
export SNAPAPI_KEY=your_key_here
node competitor-audit.js
Sample output
| URL | CTA Count | Top CTA | Word Count | Technologies |
|---|---|---|---|---|
| stripe.com/pricing | 2 | Start for free | 1842 | React, Next.js, Stripe.js |
| notion.so/pricing | 1 | Get Notion free | 1204 | React, Segment, Intercom |
| linear.app/pricing | 1 | Start for free | 890 | React, Next.js, Cloudflare |
| vercel.com/pricing | 3 | Start Deploying | 1540 | React, Next.js, Vercel |
| render.com/pricing | 2 | Get Started | 1120 | React, Next.js |
90 seconds. All 5 pages. In one terminal window.
Three things this unlocks
Competitive CTA research. Before writing your own copy, know exactly what every competitor is saying. "Start for free" vs "Get started" vs "Try for free" — small differences that teams A/B test for months. You can see their current winner.
OG tag auditing. Swap "endpoint": "analyze" for "endpoint": "metadata" and you get OG title, OG image, description, and canonical URL for every page. Run this against your entire sitemap before a launch to find every missing og:image.
Screenshot batch. Use "endpoint": "screenshot" to capture a visual archive of competitor pages before they change. Each result includes a base64-encoded PNG. Store them dated — it's a free visual history.
Scaling it
Replace the hardcoded array with a CSV reader:
const fs = require('fs');
const COMPETITORS = fs.readFileSync('urls.csv', 'utf8')
.split('\n').map(l => l.trim()).filter(Boolean);
Save results to JSON:
fs.writeFileSync('audit.json', JSON.stringify(results, null, 2));
Schedule with cron:
0 9 * * 1 SNAPAPI_KEY=your_key node /path/to/competitor-audit.js >> ~/audit.log
Every Monday morning, fresh competitive intelligence waiting in your terminal.
Free API key
100 calls/month — enough to run this audit weekly on 14 competitors with zero cost.
→ snapapi.tech/start — key active in 30 seconds, no credit card.
Top comments (0)