A Node.js Trends API client is a Bearer-authenticated POST to https://api.trendsapi.ai/api, then a second JSON.parse on the body string. On 2026-08-09, Google Search interest for Node.js sat at 42.0 on 2026-08-08 with 30D growth of -35.38%, 3M of -49.4%, 6M of 16.67%, and 12M of 90.91%. The same pull on the npm source showed react at score 100.0 with 162,776,333 weekly downloads on 2026-08-08 and 12M volume growth of 289.26%. That pairing is the point of the integration: search interest and package volume share one JSON contract.
Minimal fetch client
Node 18+ ships fetch. Set TRENDSAPI_API_KEY and keep the double parse in one helper. Free tier allows 100 successful requests per month. Only HTTP 200 responses count against quota. Starter is 5,000, Pro is 25,000, Business is 100,000.
const API_URL = "https://api.trendsapi.ai/api";
const API_KEY = process.env.TRENDSAPI_API_KEY;
async function trendsApi(payload) {
const res = await fetch(API_URL, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
const envelope = await res.json();
// body is a JSON string; parse it a second time
return JSON.parse(envelope.body);
}
const growth = await trendsApi({
mode: "get_growth",
source: "google search",
keyword: "Node.js",
percent_growth: ["30D", "3M", "6M", "12M"],
});
console.log(growth.results[0].growth);
The first mistake most clients make is reading envelope.body.results. That fails because body is still a string after res.json().
Google Search growth for Node ecosystem terms
Pulled on 2026-08-09 with source set to google search. Recent points land on 2026-08-08.
| Keyword | Period | Recent value | Baseline date | Baseline value | Growth |
|---|---|---|---|---|---|
| Node.js | 30D | 42.0 | 2026-07-11 | 65.0 | -35.38% |
| Node.js | 3M | 42.0 | 2026-05-09 | 83.0 | -49.4% |
| Node.js | 6M | 42.0 | 2026-02-07 | 36.0 | 16.67% |
| Node.js | 12M | 42.0 | 2025-08-09 | 22.0 | 90.91% |
| TypeScript | 7D | 32.0 | 2026-08-01 | 49.0 | -34.69% |
| TypeScript | 30D | 32.0 | 2026-07-11 | 79.0 | -59.49% |
| TypeScript | 3M | 32.0 | 2026-05-09 | 89.0 | -64.04% |
| TypeScript | 12M | 32.0 | 2025-08-09 | 49.0 | -34.69% |
| react | 7D | 46.0 | 2026-08-01 | 51.0 | -9.8% |
| react | 30D | 46.0 | 2026-07-11 | 71.0 | -35.21% |
| react | 3M | 46.0 | 2026-05-09 | 96.0 | -52.08% |
| react | 12M | 46.0 | 2025-08-09 | 60.0 | -23.33% |
| Next.js | 7D | 13.0 | 2026-08-01 | 21.0 | -38.1% |
| Next.js | 30D | 13.0 | 2026-07-11 | 54.0 | -75.93% |
| Next.js | 3M | 13.0 | 2026-05-09 | 61.0 | -78.69% |
| Next.js | 12M | 13.0 | 2025-08-09 | 23.0 | -43.48% |
Node.js is up 90.91% over 12M while short windows are down. Next.js sits at 13.0 with a 30D drop of -75.93%. Keep both windows in the payload; they answer different questions.
For source docs and field notes, see Google Search trends. For a Python twin of this client pattern, see the Python Trends API guide.
npm volumes on the npm source
Keywords on source: "npm" must be exact package names as listed on the registry. Pulled on 2026-08-09 with custom dates ending on 2026-08-08 so the comparison skips a sparse tip week that returned score 0.0 and volume 0 on 2026-08-15 for preset windows.
| Package | Window | Score | Recent volume | Baseline volume | Score growth | Volume growth |
|---|---|---|---|---|---|---|
| react | ~30D | 100.0 | 162,776,333 | 153,316,909 | 6.16% | 6.17% |
| react | ~3M | 100.0 | 162,776,333 | 126,151,303 | 29.03% | 29.03% |
| react | ~6M | 100.0 | 162,776,333 | 86,477,138 | 88.32% | 88.23% |
| react | ~12M | 100.0 | 162,776,333 | 41,816,890 | 289.11% | 289.26% |
| next | ~30D | 95.2 | 52,322,903 | 44,699,800 | 17.1% | 17.05% |
| next | ~3M | 95.2 | 52,322,903 | 32,833,548 | 59.46% | 59.36% |
| next | ~6M | 95.2 | 52,322,903 | 35,841,233 | 46.01% | 45.99% |
| next | ~12M | 95.2 | 52,322,903 | 16,164,594 | 223.81% | 223.69% |
| express | ~1M to Jul 25 | 96.1 | 122,886,309 | 109,631,397 | 12.14% | 12.09% |
| express | ~3M to Jul 25 | 96.1 | 122,886,309 | 93,038,148 | 32.01% | 32.08% |
| express | ~6M to Jul 25 | 96.1 | 122,886,309 | 60,193,051 | 104.03% | 104.15% |
| express | ~12M to Jul 25 | 96.1 | 122,886,309 | 43,787,159 | 180.99% | 180.64% |
react hit the local max score of 100.0 on 2026-08-08. next trailed at 95.2 with faster 30D score growth (17.1% vs 6.16%). express still shows 180.99% score growth over ~12M ending 2026-07-25.
Custom date objects in percent_growth look like this:
const npmGrowth = await trendsApi({
mode: "get_growth",
source: "npm",
keyword: "react",
percent_growth: [
{ name: "30d_to_aug8", recent: "2026-08-08", baseline: "2026-07-11" },
{ name: "12m_to_aug8", recent: "2026-08-08", baseline: "2025-08-09" },
],
});
Field notes for package downloads live on the npm trends page. For a product-demand walkthrough that uses the same Node helper against Amazon and Google Shopping, see soccer cleats multi-source signals in Node.
get_time_series for charts and alerts
When a dashboard needs every weekly point, switch mode to get_time_series. The react series returned 261 points on 2026-08-09. Recent complete weeks included 2026-08-01 at score 99.7 with volume 162,348,333 and 2026-08-08 at score 100.0 with volume 162,776,333. The next stub week 2026-08-15 returned 0.0 / 0; treat that tip as incomplete until volume is non-zero.
const series = await trendsApi({
mode: "get_time_series",
source: "npm",
keyword: "react",
});
const complete = series.filter((row) => row.volume > 0);
const last = complete[complete.length - 1];
console.log(last.date, last.value, last.volume);
Use get_top_trends only for live boards with no keyword. On 2026-08-09 the Google Trends board listed perez hilton at rank 1 and spokane fires at rank 2 as of 2026-08-09T10:01:34Z.
Error handling and quotas
Check HTTP status before parsing. Then check statusCode on the envelope. Growth rows can return per-period status: "error" with codes such as collapsed_range or date_out_of_range while other periods still succeed. Log the period and keep the successful rows.
Quota reminder: only successful 200 responses count. A failed auth call does not burn the free 100. Cache responses for cron jobs that poll the same keyword every hour.
When to use this over scrapers
A Node scraper against unofficial Google Trends endpoints breaks when cookies or consent walls change. Trends API keeps one endpoint, Bearer auth, and a 0-100 score across Google Search, npm, Amazon, TikTok, and the rest of the documented source list. For broader alternative framing, see the Google Trends API alternative page.