The Node.js client for SEO Score API is at 1.3.0 on npm. It mirrors the Python release we shipped at the same time: a new compare() function for side-by-side URL diffs, full history() and historyDomains() timeseries access, and webhook alerts on the monitor system (Slack-formatted automatically when you point it at an incoming webhook).
Install or upgrade with:
npm install seoscoreapi@latest
Or with pnpm/yarn — same name, no native dependencies, runs anywhere Node 18+ has fetch available.
What's new in 1.3
| Function | Endpoint | Tier |
|---|---|---|
compare(urls, apiKey) |
POST /compare |
Basic+ |
history(url, apiKey, opts) |
GET /history |
Starter+ |
historyDomains(apiKey) |
GET /history/domains |
Starter+ |
addMonitor(url, apiKey, { webhookUrl, alertThreshold }) |
POST /monitors |
Paid |
addMonitor is backwards compatible — the legacy addMonitor(url, apiKey, "weekly") form still works, but if you want webhooks you'll pass an options object instead.
1. Compare your page against 2–4 competitors in one call
compare() accepts 2–5 URLs and returns each one's score plus a diff block telling you who is ahead, per category, per pair:
const { compare } = require("seoscoreapi");
const result = await compare(
[
"https://acme.com/pricing",
"https://competitor-a.com/pricing",
"https://competitor-b.com/pricing",
],
process.env.SEOSCORE_API_KEY,
);
for (const url of result.urls) {
console.log(`${url.url}: ${url.score} (${url.grade})`);
}
for (const gap of result.diff.category_gaps) {
console.log(`${gap.category}: leader ${gap.leader} (+${gap.gap.toFixed(1)})`);
}
This one's Basic plan ($15/mo) and up. It's the call we use to power the agency-style "where do we stand?" dashboards customers have been building on top of the API.
2. Pull historical scores for any URL
If your account has been running audits on a paid plan, every audit's full score breakdown is already in our database. history() returns the full timeseries plus a summary block:
const { history } = require("seoscoreapi");
const data = await history(
"https://acme.com",
process.env.SEOSCORE_API_KEY,
{ limit: 90 },
);
console.log(`${data.count} audits tracked`);
console.log(`First: ${data.summary.first_score}`);
console.log(`Latest: ${data.summary.latest_score}`);
console.log(`Total delta: ${data.summary.total_delta.toFixed(1)}`);
Retention windows are tied to your tier — Starter sees 30 days, Basic 90, Pro a year, Ultra unlimited. The deeper write-up on what's in the history block is in the historical comparison post.
3. One-shot view of every domain you've audited
historyDomains() returns one row per domain on your key, with the latest score and a 30-day trend:
const { historyDomains } = require("seoscoreapi");
const domains = await historyDomains(process.env.SEOSCORE_API_KEY);
domains.sort((a, b) => (a.trend_30d ?? 0) - (b.trend_30d ?? 0));
console.log("Worst trends this month:");
for (const d of domains.slice(0, 10)) {
const arrow = (d.trend_30d ?? 0) < 0 ? "↓" : "↑";
console.log(` ${d.domain.padEnd(40)} ${d.latest_score} ${arrow}${Math.abs(d.trend_30d ?? 0).toFixed(1)}`);
}
Single API call, one row per domain. Use it for a Slack digest, an agency dashboard, or to feed an LLM that's writing a quarterly recap.
4. Get Slack alerts on score drops
addMonitor() now takes a webhookUrl and alertThreshold:
const { addMonitor } = require("seoscoreapi");
await addMonitor(
"https://acme.com",
process.env.SEOSCORE_API_KEY,
{
frequency: "daily",
webhookUrl: "https://hooks.slack.com/services/T0/B0/xxxx",
alertThreshold: 5, // alert when the score drops 5+ points
},
);
If the webhook URL points at hooks.slack.com, the payload is auto-formatted as Block Kit so it renders cleanly. Any other https endpoint gets the raw event JSON — wire it into PagerDuty, Discord, n8n, or your own service.
Three places to drop this into a Node project
Express middleware that runs an SEO audit on demand
const express = require("express");
const { audit } = require("seoscoreapi");
const app = express();
app.get("/seo-check", async (req, res) => {
const result = await audit(req.query.url, process.env.SEOSCORE_API_KEY);
res.json({
score: result.score,
grade: result.grade,
delta: result.history?.delta,
top_issues: (result.priorities || []).slice(0, 3),
});
});
app.listen(3000);
The result.history.delta field is what makes this useful in production: every audit response on a paid plan tells you whether the score moved since last time and by how much.
Next.js API route for an internal dashboard
// app/api/seo-snapshot/route.js
import { historyDomains } from "seoscoreapi";
export async function GET() {
const domains = await historyDomains(process.env.SEOSCORE_API_KEY);
return Response.json({
domains: domains.map((d) => ({
domain: d.domain,
score: d.latest_score,
grade: d.latest_grade,
trend_30d: d.trend_30d,
})),
});
}
That's the entire backend for an internal "all our brands at a glance" page.
Stand-alone weekly CLI you run from cron
#!/usr/bin/env node
const { historyDomains } = require("seoscoreapi");
const domains = await historyDomains(process.env.SEOSCORE_API_KEY);
const dropped = domains.filter((d) => (d.trend_30d ?? 0) <= -2.0);
if (dropped.length === 0) {
console.log("All domains stable.");
process.exit(0);
}
console.log(`${dropped.length} domains down 2+ points:`);
for (const d of dropped) {
console.log(` ${d.domain}: ${d.latest_score} (${d.trend_30d.toFixed(1)} 30d)`);
}
process.exit(1);
Pipe the output to email or wire it to a Slack incoming webhook, schedule it weekly with cron or a CI pipeline, and you've got an automated Monday-morning report.
Upgrading from 1.2
Strict additive update. addMonitor() accepts the new options object form or the legacy (url, apiKey, "daily") string form, so existing code keeps working. The new functions are pure additions.
npm install seoscoreapi@latest
The full reference is in the README and at /docs. If you don't have a key yet, grab a free one or start on Starter for $5/mo.