npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@arham-rumi/google-trends-api

v0.2.4

Published

Modern, typed, unofficial Google Trends client for Node.js.

Readme

@arham-rumi/google-trends-api

CI Live Integration

A modern, typed, unofficial Google Trends client for Node.js.

This package is not affiliated with, maintained by, or endorsed by Google. It uses endpoints that Google may change without notice.

Features

  • TypeScript-first API with generated declarations
  • ESM and CommonJS builds
  • Interest over time for up to five terms or topics
  • Interest by country, region, city, or DMA
  • Related queries and related topics
  • Trending Now RSS data
  • Search-term and topic autocomplete
  • Cookie-aware sessions, timeouts, retries, abort signals, and typed errors
  • Lazy session warm-up, serialized requests, deduplication, caching, and 429 cooldowns

Requirements

  • Node.js 22.14.0 or newer

Installation

npm install @arham-rumi/google-trends-api

Quick start

import { createClient } from '@arham-rumi/google-trends-api';

const trends = createClient({
  locale: 'en-US',
  timeoutMs: 15_000,
  retries: 2,
});

const result = await trends.interestOverTime({
  keywords: ['node.js', 'deno'],
  geo: 'US',
  timeRange: 'today 12-m',
});

for (const point of result.timeline) {
  console.log(point.date, point.values);
}

Google Trends values are normalized relative scores, usually from 0 to 100. They are not absolute search volumes.

Rate-limit protection and cache metadata

By default, the client serializes requests, spaces them by 2.5 seconds, deduplicates identical concurrent calls, and caches successful results for 15 minutes. HTTP 429 responses are never retried immediately. When a stale cached result is available, it is returned during the shared cooldown.

import { getResultMetadata } from '@arham-rumi/google-trends-api';

const result = await trends.interestOverTime({ keywords: 'node.js' });
console.log(getResultMetadata(result));
// { source: 'network' | 'cache' | 'stale-cache', stale: boolean, cachedAt?: Date }

trends.clearCache();
console.log(trends.cooldownRemainingMs);

The cache is per client instance and stored in memory. It does not bypass Google limits; it reduces avoidable requests and keeps applications useful during temporary 429 periods.

Client configuration

const trends = createClient({
  locale: 'en-US',
  timezone: 0,
  timeoutMs: 10_000,
  retries: 2,
  userAgent: 'my-app/1.0 (+https://example.com)',
  rateLimit: {
    minIntervalMs: 2_500,
    cooldownMs: 60_000,
  },
  cache: {
    ttlMs: 15 * 60_000,
    staleIfErrorMs: 24 * 60 * 60_000,
    maxEntries: 100,
  },
});

| Option | Default | Description | | ----------- | --------------- | --------------------------------------------------- | | locale | en-US | Locale sent to Google Trends. | | timezone | 0 | Google Trends timezone offset in minutes. | | timeoutMs | 10000 | Timeout for each HTTP attempt. | | retries | 2 | Additional attempts for temporary non-429 failures. | | userAgent | Package default | User agent sent with requests. | | rateLimit | See below | Request spacing and shared HTTP 429 cooldown. | | cache | See below | Fresh and stale in-memory result caching. | | fetch | Native fetch | Optional custom fetch implementation. |

Interest over time

const result = await trends.interestOverTime({
  keywords: ['typescript', 'javascript'],
  geo: 'PK',
  timeRange: 'now 7-d',
  category: 0,
  property: '',
});

console.log(result.timeline);
console.log(result.averages);

keywords accepts one value or up to five values. A topic machine ID returned by autocomplete() can also be used as a keyword.

Interest by region

import { INTEREST_BY_REGION_RESOLUTIONS, createClient } from '@arham-rumi/google-trends-api';

console.log(INTEREST_BY_REGION_RESOLUTIONS);

const result = await trends.interestByRegion({
  keywords: 'artificial intelligence',
  geo: 'US',
  resolution: 'REGION',
  includeLowSearchVolumeGeos: true,
});

console.log(result.regions);

Supported resolutions are COUNTRY, REGION, CITY, and DMA. Availability depends on the selected geography and Google Trends data.

Related queries

const results = await trends.relatedQueries({
  keywords: ['node.js', 'bun'],
  geo: 'US',
  timeRange: 'today 3-m',
});

for (const result of results) {
  console.log(result.keyword, result.top, result.rising);
}

Related topics

const results = await trends.relatedTopics({
  keywords: 'machine learning',
  geo: 'US',
});

console.log(results[0]?.top);
console.log(results[0]?.rising);

Trending Now

const result = await trends.trendingNow({
  geo: 'PK',
  limit: 10,
});

for (const trend of result.trends) {
  console.log(trend.title, trend.approxTraffic, trend.publishedAt);
}

geo must be a two-letter country or territory code.

Autocomplete

const result = await trends.autocomplete({
  keyword: 'tesla',
  limit: 10,
});

for (const suggestion of result.suggestions) {
  console.log(suggestion.kind, suggestion.title, suggestion.keyword);
}

For topic suggestions, suggestion.keyword is the Google Knowledge Graph machine ID that can be passed to other methods.

Search properties

import { GOOGLE_TRENDS_PROPERTIES } from '@arham-rumi/google-trends-api';

console.log(GOOGLE_TRENDS_PROPERTIES);

Valid property values are:

| Value | Search surface | | ----------- | --------------- | | '' | Web Search | | 'images' | Image Search | | 'news' | News Search | | 'youtube' | YouTube Search | | 'froogle' | Google Shopping |

Cancellation

Every public request method accepts an AbortSignal:

const controller = new AbortController();

const request = trends.interestOverTime({
  keywords: 'node.js',
  signal: controller.signal,
});

controller.abort();
await request;

Error handling

import {
  GoogleTrendsError,
  RateLimitError,
  RequestTimeoutError,
  createClient,
} from '@arham-rumi/google-trends-api';

try {
  await createClient().trendingNow({ geo: 'US' });
} catch (error) {
  if (error instanceof RateLimitError) {
    console.error('Rate limited. Retry later.', error.retryAfterMs);
  } else if (error instanceof RequestTimeoutError) {
    console.error('Request timed out.');
  } else if (error instanceof GoogleTrendsError) {
    console.error(error.code, error.message);
  } else {
    throw error;
  }
}

Exported error classes include:

  • HttpStatusError
  • RateLimitError
  • RequestTimeoutError
  • RequestAbortedError
  • NetworkError
  • InvalidResponseError
  • WidgetNotFoundError

CommonJS

const { createClient } = require('@arham-rumi/google-trends-api');

const trends = createClient();

Development

npm install
npm run check

Run the repository example after building:

npm run build
node examples/basic.mjs

Run the opt-in live integration suite:

npm run test:integration

Run the broad real-data smoke test against the built package:

npm run smoke:live

Run the deep Interest Over Time validator, which compares parsed package output with the raw Google timeline response for the same request:

npm run verify:interest-live

The live checks call Google endpoints and may fail when Google changes an endpoint, presents a challenge page, or rate-limits the runner. They intentionally remain separate from the deterministic unit-test pipeline. GitHub Actions runs the live integration suite weekly and also supports manual runs.

Limitations and responsible use

Google Trends does not provide these internal endpoints as a stable public contract. Responses, tokens, rate limits, or endpoint behavior can change. Applications should handle errors, cache appropriate results, avoid high-frequency polling, and comply with applicable Google terms and policies.

License

MIT © 2026 arham-rumi contributors