TrendFlow について
TrendFlowは、Google Trendsのデータを取得・出力するJavaScript/TypeScriptライブラリで、トレンド調査向けのMCPサーバーも別途提供します。地域・期間別の関心度や関連クエリ、トピック、急上昇検索を扱えます。
主な機能
- 01期間別・地域別の関心度取得
- 02関連クエリとトピック候補の検索
- 03検索トレンドの成長率と規模の取得
- 04CSV・JSON出力
- 05プロキシプールのローテーション
活用シーン
- 01地域や期間ごとの検索関心度の比較
- 02トピックに関連するクエリの調査
- 03急上昇・高ボリューム検索の追跡
MCP 対応
別パッケージの `trendflow-mcp` は、トピック検索、関心度データ、関連クエリ、急上昇検索、トレンド調査向けの6つのツールと2つのリソースを提供します。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://trendflow.mory.dev/mcpclaude mcp add --transport http dev-mory-trendflow https://trendflow.mory.dev/mcp{"mcpServers":{"dev-mory-trendflow":{"type":"http","url":"https://trendflow.mory.dev/mcp"}}}Cursor で開く{"servers":{"dev-mory-trendflow":{"type":"http","url":"https://trendflow.mory.dev/mcp"}}}VS Code で開く{"mcpServers":{"dev-mory-trendflow":{"type":"http","url":"https://trendflow.mory.dev/mcp"}}}{"mcpServers":{"dev-mory-trendflow":{"serverUrl":"https://trendflow.mory.dev/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
8| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| country | any | いいえ | "US"、"GB"、"TH" などの国コード、"US-CA" などの下位地域コード、または "807" などの米国都市圏コード。空文字列は全世界を意味します。 |
詳細
Trendflow JS
Google Trends データのクエリとエクスポートに対応した、型安全な JavaScript/TypeScript ライブラリです。
trendflow-py の JavaScript 版です。
📖 ドキュメント:trendflow.mory.dev/docs/js — 両方のライブラリのガイドに加え、 ChatGPT、Claude、Cursor 向けのホスト型 MCP サーバーも掲載しています。
- GitHub:https://github.com/dariomory/trendflow-js/
- npm パッケージ:https://www.npmjs.com/package/trendflow
- API リファレンス:https://dariomory.github.io/trendflow-js/
- Python 版:https://pypi.org/project/trendflow-py/
- 作成者:Dario Mory | GitHub https://github.com/dariomory
- フリーソフトウェア:MIT ライセンス
インストール
npm install trendflow
Node.js 18 以降が必要です(グローバルな fetch を使用します)。型宣言をバンドルした ESM と CommonJS を提供しています。
使用方法
import { Client, Region, Timeframe, Resolution, SearchProperty, ExportFormat } from "trendflow";
// Initialize client (optional config)
const tf = new Client({ language: "en", timeout: 10_000 });
// --- Const objects for type safety ---
// Region.US, Region.GB, Region.DE ... (or any code: "US-CA", "807")
// Timeframe.PAST_HOUR ... PAST_5_YEARS, ALL_TIME (or "2023-01-01 2023-06-30")
// Resolution.COUNTRY, Resolution.REGION, Resolution.CITY
// SearchProperty.WEB, IMAGES, NEWS, YOUTUBE, SHOPPING
// Fetch interest over time
const data = await tf.interestOverTime(
["Python", "JavaScript", "Rust"],
Timeframe.PAST_YEAR,
Region.US,
);
console.log(data.keywords); // ["Python", "JavaScript", "Rust"]
console.log(data.granularity); // "weekly"
console.log(data.points); // TrendPoint[] — { date: Date, scores: Record<string, number> }
// Regional breakdown (region defaults to Region.US)
const regional = await tf.interestByRegion("Python", Resolution.COUNTRY);
for (const row of regional.rows) {
console.log(row.label, row.value);
}
// Trending searches right now (any country code, or omit for worldwide)
const trending = await tf.trendingNow(Region.US);
for (const item of trending.results) {
console.log(item.title, item.growth, item.volume, item.traffic);
// "fifa world cup 2026" 3650 6 "+3,650%"
}
// Related queries (region defaults to worldwide)
const related = await tf.relatedQueries("machine learning", { region: Region.GB });
for (const query of related.top) console.log(query.term, query.value);
for (const query of related.rising) console.log(query.term, query.breakout);
// --- Narrowing a query ---
// Every query method takes an optional category and search property, and any of them
// accepts a custom date range and a sub-region or metro code in place of the named values.
// "jaguar" the car, on YouTube, in California, over the first half of 2023
const jaguar = await tf.interestOverTime(["jaguar"], "2023-01-01 2023-06-30", "US-CA", {
category: 47, // Autos & Vehicles — disambiguates without needing a topic id
searchProperty: SearchProperty.YOUTUBE,
});
// --- Exports ---
data.toArray(); // [{ date: Date, Python: 80, ... }] — plain objects, the JS answer to DataFrames
data.toJSON(); // same rows with ISO 8601 date strings (also drives JSON.stringify)
data.toCSV(); // CSV text
// Node.js only — writes UTF-8 to disk
await data.export(ExportFormat.CSV, "trends.csv");
await data.export(ExportFormat.JSON, "trends.json");
エラー
リクエストに失敗すると ResponseError がスローされます。HTTP 429 の場合は、そのサブクラスである TooManyRequestsError がスローされます。
どちらにも .status と生の .response が含まれます。
import { TooManyRequestsError } from "trendflow";
try {
await tf.interestOverTime(["Python"], Timeframe.PAST_YEAR, Region.US);
} catch (error) {
if (error instanceof TooManyRequestsError) {
// Google is rate-limiting this IP — back off and retry later.
}
}
トレンド取得バックエンド:RPC と RSS
Google はトレンド検索を 2 つの方法で公開しています。これらは互換性がないため、backend で
選択できます。
"rpc"(batchexecute) | "rss"(フィード) | |
|---|---|---|
| 項目数 | 50 | 10 |
| ペイロード | 約 2 KB の JSON | 約 21 KB の XML |
| 増加率と検索ボリューム | ✅ | ❌ — "2000+" のような区分 |
| ニュース記事 | ❌ | ✅ |
window の選択 | ✅ | Google に無視されます |
| 全世界 | ✅ | ❌ 国のみ |
const rss = await tf.trendingNow(Region.US, { backend: "rss" });
rss.source; // "rss"
rss.results[0].articles;
// [{ title: "...", url: "https://...", source: "Buffalo News", picture: "https://..." }]
"auto"(デフォルト)は RPC を試し、失敗した場合はフィードにフォールバックします。意図的に RPC を先に試します。
RPC は実際の増加率とともに 5 倍の項目を返すため、デフォルトを RSS にすると結果の質が知らないうちに低下します。記事が必要な場合は "rss" を選んでください。記事は RPC では取得できません。また、RPC の ID が古くなった場合に、別の情報源として使うこともできます。
フィードであっても、フィードは軽量な取得方法ではありません。また、Google はフィードでは hours、sort、count を無視し、常に同じ 10 件を返します。
トピックと検索候補
Google は検索語句(文字列そのもの)とトピック(あらゆる表記や言語におけるエンティティ)を区別しています。suggestions() でトピックを検索できます。各クエリメソッドはすでにトピックを受け取れるため、キーワードを渡す箇所に mid を渡してください。
const topics = await tf.suggestions("artificial intelligence");
// [{ mid: "/m/0mkz", title: "Artificial intelligence", type: "Professional field" }]
const data = await tf.interestOverTime(
[topics[0].mid, "artificial intelligence"],
Timeframe.PAST_YEAR,
Region.US,
);
// { "/m/0mkz": 62, "artificial intelligence": 1 }
この違いが重要です。トピックのスコアは 62 ですが、文字列そのもののスコアは 1 です。これは、実際に検索されるあらゆる言い回しや翻訳を集約するためです。
suggestions() に Cookie やプロキシは必要ありません。trendingNow() と同様に、widgetdata エンドポイントが 429 で拒否する IP からでも応答します。type を使うと同名のエンティティを区別できます("Nike" なら企業と女神の両方が返されます)。Google が値を省略した場合、type は null になります。
レート制限
Google Trends はデータセンターの IP や共有 IP に対して厳しいレート制限を設けているため、その日の最初のリクエストでも 429 がよく発生します。重要な点は次の 2 つです。
- User-Agent。 Google は、Node の HTTP クライアントが送信するデフォルトのエージェント文字列に対し、リクエスト数がどれほど少なくても
429を返します。そのため、このライブラリはデフォルトでブラウザーの User-Agent を送信します。headersを上書きする場合は、現実的な値を指定してください。 - IP の評価。 IP が一度フラグ付けされると、ヘッダーに関係なくすべてのリクエストに
429が返されます。復旧するには、住宅用プロキシ経由で接続してください。
プロキシプールの使用
プロキシ URL のリストを渡すと、クライアントは自動的にローテーションし、クエリが拒否されるたびに次のプロキシに切り替えます。
import { Client, Region, Timeframe } from "trendflow";
const tf = new Client({
proxies: [
"http://user:[email protected]:7000",
"http://user:[email protected]:7000",
],
maxProxyAttempts: 3, // defaults to the pool size, capped at 5
onProxyRotate: ({ attempt, error }) => console.warn(`rotated after ${attempt}:`, error),
});
const data = await tf.interestOverTime(["Python"], Timeframe.PAST_YEAR, Region.US);
console.log(tf.currentProxy); // the proxy that answered
プロキシをサポートするには、オプションのピア依存関係である undici が必要です。npm install undici を実行してください。エントリーには URL のみを指定するため、プール内でプロバイダーを混在させることもできます。同じローテーションゲートウェイを繰り返し指定する方法も使えます。各エントリーは個別の接続を使うため、新しい出口 IP が割り当てられます。
ローテーションはリクエストごとではなく、クエリごとに行われます。これは重要です。 Google は NID Cookie とウィジェットトークンを、それらをリクエストした IP に紐付けます。そのため、1 つのクエリは同じ出口 IP で完了する必要があります。後続の widgetdata 呼び出しを別の IP から送信すると、即座に 429 が返されます。プールはクエリ全体で 1 つのプロキシを固定し、失敗時にのみ切り替え、そのたびに Cookie jar を再初期化します。同じ理由から、プロバイダーで選択できる場合は、リクエストごとにローテーションするエンドポイントではなく、スティッキーセッションをプールに指定してください。
別の IP でも解決できないエラー(404 や、Google が batchexecute RPC ID の名前を変更したときに発生する UnknownRpcError など)の場合、ローテーションはスキップされます。
プロキシの入手先
Google の 429 を実際に解消できるのは住宅用プロキシです。このライブラリで検証済みです。
| プロバイダー | 備考 | エンドポイント形式 |
|---|---|---|
| Decodo(旧 Smartproxy) | 最も安価なエントリーティアです。従量課金も利用できます。このライブラリのライブテストの検証に使用しました。 | http://user:[email protected]:7000 |
const tf = new Client({
proxies: ["http://user:[email protected]:7000"],
});
登録時にスティッキーセッションを選択してください。リクエストごとにローテーションするエンドポイントでは、前述の Cookie とトークンの紐付けが崩れます。共有の住宅用プロキシプールは、Google Trends に対して使い切られる場合があります。その場合、有効なプロキシでも 429 が返されます。このために maxProxyAttempts が用意されています。
独自のクライアントを使用する
ロギング、キャッシュ、カスタムルーティングを行う場合は、代わりに fetch を渡してください(proxies との併用はできません。両方を渡すとライブラリが通知します)。
import { ProxyAgent, fetch as undiciFetch } from "undici";
const agent = new ProxyAgent("http://user:[email protected]:7000");
const tf = new Client({
fetch: ((input, init = {}) =>
undiciFetch(input, { ...init, dispatcher: agent })) as typeof globalThis.fetch,
});
ブラウザー/Next.js
export() を除くすべてのメソッドは、fetch が使える場所ならどこでも動作します。ただし、Google Trends は CORS ヘッダーを送信しないため、ブラウザーの JavaScript からの呼び出しはブロックされます。このライブラリはサーバー側(Route Handlers、Server Actions、API routes)で使用し、結果をクライアントに渡してください。
MCP サーバー
エージェントが Google Trends に直接クエリできるよう、ライブラリとともに MCP サーバー trendflow-mcp が提供されています。これは独立したパッケージです。ライブラリのランタイム依存関係はゼロのままです。
claude mcp add trendflow -- npx -y trendflow-mcp
6 つのツール(search_topics、get_interest_over_time、get_interest_by_region、get_related_queries、get_trending_now、research_trend)と 2 つのリソースがあります。詳しくは mcp/README.md を参照してください。
機能の同等性
現在:trendflow-py 0.2.0 · trendflow 0.1.0。バージョンは独立しており、それぞれの変更履歴で対応するもう一方のリリースを相互に参照しています。
| 機能 | Python — trendflow-py | JS — trendflow |
|---|---|---|
| 時系列の検索インタレスト | ✅ | ✅ |
| 地域別の検索インタレスト | ✅ | ✅ |
| 現在のトレンド | ✅ | ✅ |
| トレンドの成長率とボリューム | ✅ | ✅ |
| 任意の国コードのトレンド | ✅ | ✅ |
| トレンド関連ニュース記事(RSS) | ✅ | ✅ |
| トレンドバックエンドの選択 | ✅ | ✅ |
| 関連クエリ | ✅ | ✅ |
| 検索候補 | ✅ suggestions() | ✅ suggestions() |
| トピック(エンティティの mid)によるクエリ | ✅ | ✅ |
| CSV / JSON エクスポート | ✅ | ✅ |
| ローテーションプロキシプール | ✅ | ✅ |
| デフォルトのブラウザー User-Agent | ✅ | ✅ |
| 完全な地域階層 | ✅ geo_list() | ✅ geoList() |
| RPC ID の上書き | ✅ | ✅ |
| pandas DataFrame | ✅ to_dataframe() | ❌ 該当なし |
| プレーンオブジェクトの行 | ❌ 該当なし | ✅ toArray() |
| ESM + CommonJS + 型定義 | ❌ 該当なし | ✅ |
| MCP サーバー | 🔜 予定 | ✅ trendflow-mcp |
| CLI | ✅ | 🔜 予定 |
現在のトレンド
Google は hottrends/visualize/internal/data エンドポイントを廃止し、api/dailytrends と api/realtimetrends も廃止しました。3 つとも HTTP 404 を返すようになっています。このライブラリは、代わりに trends.google.com 自身が使用している batchexecute RPC を呼び出します。0.2.0 以降の trendflow-py も同様です。この RPC は、旧エンドポイントより多くのデータを返します。
const trending = await tf.trendingNow(Region.US);
// { title: "fifa world cup 2026", growth: 3650, volume: 6, traffic: "+3,650%", articles: [] }
旧エンドポイントと比べて、実用上の利点は 3 つあります。
- タイトルだけでなく、成長率とボリュームも取得できます。
growthは期間内の上昇率、volumeは相対的な検索ボリュームのインデックスです。 - 旧エンドポイントで必要だった 16 個のハードコードされた名前に限らず、任意の国コードを指定できます。 以前は拒否されていた全世界も指定できます。
- Cookie が不要で、レート制限も大幅に緩やかです。 この RPC は、widgetdata エンドポイントから
429を受ける IP にも応答するため、trendingNow()はプロキシなしでも機能することがよくあります。
このバックエンドでは articles は空です。RPC に記事へのリンクが含まれていないためです。各トレンドに関連するニュース記事を取得するには、{ backend: "rss" } を渡してください。
TrendingWindow を使って期間を選択できます。
import { TrendingWindow } from "trendflow";
await tf.trendingNow(Region.US, { window: TrendingWindow.RISING }); // default: fastest-growing
await tf.trendingNow(Region.US, { window: TrendingWindow.TOP }); // highest-volume
window は Google の非公開パラメーターです。名前を付けて説明する価値のある動作をするのは、この 2 つの値だけです。4 から 12 までのほかの整数を指定しても、さまざまな直近期間のデータが返されます。また、数値をそのまま渡すこともできます。
未実装:CAPTCHA が必要な RPC
同じ batchexecute エンドポイントでは、より高精度な時系列(公開 API が返す丸められた 0~100 の値ではなく、浮動小数点値)と、キーワードを指定した関連クエリも公開されています。どちらも reCAPTCHA Enterprise トークンが必要で、トークンなしでは空のペイロードが返されるため、このライブラリでは実装していません。これらのデータは、ドキュメント化された widgetdata エンドポイントを使う interestOverTime() と relatedQueries() から引き続き取得できます。
API の対応関係
| Python | JavaScript |
|---|---|
interest_over_time() | interestOverTime() |
interest_by_region() | interestByRegion() |
trending_now() | trendingNow() |
related_queries() | relatedQueries() |
to_dataframe() | toArray() |
export(fmt, path) | export(fmt, path) — Node のみ。さらに toCSV() / toJSON() |
主な違い:
- すべて非同期です。 4 つのクエリメソッドはすべて Promise を返します。
timeoutの単位はミリ秒です(JS の慣例)。秒ではありません。- 列挙型は
as constオブジェクトです。 そのため、Region.USは文字列"US"であり、型が求められる箇所には有効な文字列リテラルを指定できます。 - 結果は型付きのプレーンオブジェクトです。 変換メソッドを備えているため、
InterestOverTimeResultのみクラスで、それ以外はインターフェースです。
開発
git clone [email protected]:dariomory/trendflow-js.git
cd trendflow-js
npm install
npm test # vitest — 60 tests, fully offline against a stubbed fetch
npm run qa # typecheck + test + build
ユニットテストではネットワークに接続しません。実際のエンドポイントを確認するには:
npm run build && npm run smoke
TRENDFLOW_PROXY_URL=http://user:pass@host:7000 npm run smoke # via a proxy
作者
Trendflow JS は、2026 年に Dario Mory によって作成されました。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。