X(旧Twitter)の「おすすめ(For You)」を決めるコードは、GitHubのxai-org/x-algorithmで公開されています。2026年1月20日の初回公開から、5月15日と8月13日に大きな追加があり、8月13日以降の約10週間で52回のコミットが入りました。10月13日と14日には、いいねの重みが0.5から0.66へ上がっています。この記事では、2026年10月23日時点のmain(コミット 07d159b)を根拠に、おすすめが決まる順序、行動ごとの重み、流布している通説とコードの違いを整理します。後半では、同じXの投稿を自社の口コミとして集めて分析する仕組みを、X APIとPythonで組む手順と費用まで示します。
まとめ:Xアルゴリズム最新の要点(2026年10月23日時点)
- おすすめは、フォロー中の新着(Thunder)とフォロー外の候補(Phoenix検索・SimClusters・人気投稿の共有リスト)を集め、同じTransformerモデル(Phoenix)で順位付けして作られます。
- 基本スコアは、行動の予測確率や滞在時間の予測値に重みを掛けた合計です。10月14日以降の重みは、いいね0.66、リプライ5.0、リンクコピーでの共有20.0、「興味がない」-52.272、通報-234.0などです。重みは件数ではなく確率に掛かります。
- いいねの引き上げで、いいねを基準にした倍率は縮みました。リプライはいいねの10倍から約7.6倍に、通報は-468倍から約-355倍になっています。
- 10月22日から、候補が2,800件を超えると候補元ごとの比率を保って間引く処理が、スコア計算の前に入りました。
- フォロー外の投稿は0.75倍、同じ投稿者の2件目以降は減衰します。新規投稿者枠は9月30日以降、フォロワー5万人以下・ホーム表示200回未満・投稿から2時間以内の元投稿が対象です。
- 「リプライ75倍」は2023年版の係数75.0との混同です。Premium加入、外部リンク、保存(ブックマーク)を直接加点・減点する重みは、10月23日時点のスコア式にありません。
- Xの口コミを分析するなら、おすすめ欄ではなくX APIの直近7日検索を時系列順で取ります。Post読み取りは1件0.005ドルで、1日300件なら月45ドル前後です。
GitHub公開コード xai-org/x-algorithm の更新履歴(2026年1月〜10月)
TechCrunch(2026年1月20日)によると、イーロン・マスク氏は2026年1月に新アルゴリズムのコードを7日以内に公開するとXに投稿し、今後4週間ごとにアルゴリズムの透明性を提供すると約束しました。実際のリポジトリは1月20日に作成されましたが、次の大きな追加は4週間後ではなく5月15日でした。8月13日からは、本番の既定値をコードへ反映するcronのコミットが続き、10月9日から23日までの2週間にも9回入っています。
| 日付 | 主な変更 |
|---|---|
| 2026-01-20 | 初回公開(4コンポーネント) |
| 2026-05-15 | grox・広告挿入・推論パイプライン |
| 2026-08-13 | 重み・表示制御・SimClusters公開 |
| 2026-08-25 | 滞在0.0→0.05、動画視聴品質→0.0 |
| 2026-09-17 | 新規投稿者枠を24時間→48時間 |
| 2026-09-24 | 投稿者補正をvm-rankerへ移設 |
| 2026-09-29 | クリック0.3・興味がない-47.52 |
| 2026-09-30 | 新規投稿者枠の条件を全面変更 |
| 2026-10-07 | 未探索投稿の重み0.02→0.015 |
| 2026-10-13 | いいね0.6・動画を開く0.02・滞在時間0.006 |
| 2026-10-14 | いいね0.66・興味がない-52.272 |
| 2026-10-17 | 動画カルーセルの重複除外を有効化 |
| 2026-10-22 | 候補の按分(FairShareRanking)を有効化 |
初回公開の4コンポーネントは home-mixer・thunder・phoenix・candidate-pipeline です。1月版の説明は「Grok-1から移植したTransformer」でしたが、Phoenixの現行READMEは、以前のリリースはGrok-1由来のサンプル実装で、今回は本番実装そのもの(JAXの学習コードとRustの推論エンジン)だと明記しています。Grok-1そのものの仕様はGrok-1とは?314B MoEモデルの仕様・入手方法とApache 2.0の適用範囲で扱っています。ライセンスはApache 2.0で、2023年に公開された twitter/the-algorithm(AGPL-3.0)とは別のリポジトリです。
「おすすめ」タイムラインが決まる順序:Home Mixerの4段階の処理
おすすめはリクエストごとに組み立てられます。処理の本体は home-mixer で、閲覧者の直近の行動履歴、フォロー一覧、ブロック・ミュート、ミュートしたキーワード、既読の投稿を最初に読み込みます。
候補集め:Thunder・Phoenix検索・SimClusters・人気投稿
フォロー中のアカウントの新着は thunder がメモリ上に保持し、そのまま候補にします。フォロー外は3系統です。phoenix の検索は閲覧者と投稿をそれぞれベクトル化して近い投稿を返し、simclusters は「誰が何に反応したか」でアカウントと投稿をクラスタに分けて候補を探します。READMEには、人気の新着投稿を全閲覧者で共有するリスト(popular_posts_source)も候補元として載っており、当初の中身を「フォロワーの多いアクティブなアカウントの投稿」と説明しています。推薦システム一般の分類(協調フィルタリングとコンテンツベース)はレコメンドエンジンとは?仕組み・種類と導入判断を参照してください。
スコアリング前の投稿除外:48時間・既読・候補数の按分
スコアを付ける前に、次のような投稿が落とされます。
- 投稿から48時間を超えたもの(
AgeFilter) - 自分の投稿、既に表示した投稿、同じセッションで配信済みの投稿
- ブロック・ミュート中のアカウントの投稿、ミュートしたキーワードを含む投稿
- フォローしていないアカウントのリポストとリプライ
- 新規アカウントの閲覧者に対する、反応数が基準未満のフォロー外投稿
「数週間前の投稿がおすすめに出ない」のは、この48時間の上限によるものです。見たくない話題を確実に消したいなら、ミュートしたキーワードとブロック・ミュートが最も早い段階で効きます。スコアを付ける前に候補から外すため、後段の重みに左右されません。「興味がない」はこれと違い、自分に対する予測確率を通じて以後の推薦を下げる操作です。
10月22日からは、除外の最後にfair_share_ranking_filter.rsの按分が加わりました。残った候補が2,800件(PhoenixScoresResultSize の既定値)を超えると、フォロー中・Phoenix検索・SimClustersといった候補元ごとの件数比を保ったまま2,800件に絞ります。コード内のテストでは、440件・220件・440件の計1,100件を予算1,000件に絞ると、400件・200件・400件が残ります。特定の候補元だけがスコア計算の枠を占めない仕組みで、10月21日に追加され、翌22日に既定値が有効になりました。
Phoenixのスコアリング:行動確率と滞在時間を予測する仕組み
Phoenixは閲覧者の行動履歴を読み、候補の投稿ごとに「いいねする」「リプライする」「通報する」などの確率を出します。推論時には候補同士が互いを参照しない設計(Candidate Isolation)で、同じ投稿のスコアは一緒に並ぶ他の候補に左右されません。予測値に重みを掛けて基本スコアを計算し、投稿者補正などを経て上位の投稿を選びます。
visibility-filteringによる表示可否の判定と4種類の結果
順位が付いた後、visibility-filtering が投稿ごとに表示の可否を判定します。READMEでは、答えは「通常表示(ALLOW)」「注記付きで表示(NOTICE)」「タップで開く警告の裏に置く(INTERSTITIAL)」「表示しない(DROP)」の4種類です。判定材料は、ブロックやミュートなど閲覧者自身の操作と、別システムが投稿やアカウントに付けたラベルです。ラベルは、投稿時にスパムや成人向けなどを分類する grox、フォロー関係と反応にPageRankをかけて信頼度を出す user-cred-v2、ブロック・通報の比率でアカウントを判定する agatha などが付けます。一部の除外ルールはフォロー外への推薦にだけ適用されるため、スパム疑いの投稿がフォロワーには見えておすすめには出ない、という差が生まれます。
行動ごとの重み一覧:param.rsの既定値(2026年10月23日時点)
重みは home-mixer/params/param.rs にあります(xAI公式リポジトリのparam.rs(コミット07d159b))。ファイル冒頭のコメントによれば、最終同期は2026年10月22日です。READMEによれば、実験用の値は設定システムから読み込まれ、このファイルの既定値はcronで本番の主要な値に合わせています。いいね比は、各重みを現在のいいね0.66で割った値です。
| 予測する行動 | 10月23日 | 10月9日 | いいね比 |
|---|---|---|---|
| リンクをコピーして共有 | 20.0 | 同じ | 約30倍 |
| リプライ(相互フォローの元投稿) | 5.0+15.0 | 同じ | 約30倍 |
| リプライ | 5.0 | 同じ | 約7.6倍 |
| 引用 | 5.0 | 同じ | 約7.6倍 |
| DMで共有 | 5.0 | 同じ | 約7.6倍 |
| 投稿者をフォロー | 4.0 | 同じ | 約6.1倍 |
| 共有 | 2.0 | 同じ | 約3.0倍 |
| リポスト | 1.0 | 同じ | 約1.5倍 |
| いいね | 0.66 | 0.5 | 1倍 |
| クリック後の滞在時間(連続値) | 0.4 | 同じ | 単位が異なる |
| 投稿をクリック | 0.3 | 同じ | 約0.45倍 |
| リンクを開く | 0.2 | 同じ | 約0.3倍 |
| 画像を拡大 | 0.05 | 同じ | 約0.08倍 |
| 滞在(dwell) | 0.05 | 同じ | 約0.08倍 |
| 動画を開く | 0.02 | 0.07 | 約0.03倍 |
| 滞在時間(連続値) | 0.006 | 0.004 | 単位が異なる |
| 滞在なし | -0.02 | 同じ | 約-0.03倍 |
| プロフィールをクリック | 0.0 | 同じ | 加点なし |
| 興味がない | -52.272 | -47.52 | 約-79倍 |
| ブロック | -31.2 | 同じ | 約-47倍 |
| ミュート | -58.8 | 同じ | 約-89倍 |
| 通報 | -234.0 | 同じ | 約-355倍 |
読み方で一番誤解が多いのは、重みが件数ではなく確率に掛かる点です。READMEとコードのコメントは、「通報1件がいいね468件を打ち消す」という読み方を名指しで誤りとしています。READMEの468という数字は、いいねが0.5だったときの比です。通報の基準確率はいいねの1,000分の1未満なので、重みを大きくしないと順位に効かない、という説明が付いています。集団で通報しても、影響は主に通報者と似た閲覧者への推薦に限られます。
10月の変更は2方向です。いいねを0.5から0.66へ上げ、「興味がない」を-47.52から-52.272へ強めました。-52.272は-47.52のちょうど1.1倍です。動画を開く操作は0.07から0.02へ下がり、画面に留まった時間の連続値は0.004から0.006へ上がりました。開かせる操作より、反応と滞在を重く見る方向の調整と読めます。重みの大小だけでは寄与を比べられない点は変わりません。いいねの重みが小さくても、予測確率が高ければ重みの大きい行動より寄与が大きくなる場合があります。
保存(ブックマーク)はこの一覧にありません。Phoenix検索の索引を管理する phoenix-rankall は、いいね数・リプライ数・表示回数と並べて保存数を投稿の属性として持っています。ただ、おすすめのスコア式(param.rs)に保存の重みは無く、10月23日時点のコードからは保存数が順位にどう効くかを読み取れません。
投稿者側の補正:同一投稿者の減衰・フォロー外0.75倍・新規投稿者枠
重み付きの合計スコアには、2026年9月24日に vm-ranker へ移された補正がかかります。値は vm-ranker/params.rs の既定値で、10月23日時点でも次の4つは9月26日から変わっていません。
| 補正 | 既定値 |
|---|---|
| 同一投稿者の2件目以降 | 減衰0.5・下限0.25 |
| フォロー外の投稿 | 0.75倍 |
| トピック経由のフォロー外投稿 | 0.5倍 |
| 類似投稿の間引き(DPP) | θ=0.65・上位150件 |
同じ投稿者の投稿は、2件目が0.625倍、3件目が約0.44倍と下がり、下限の0.25倍へ近づきます。フォロー中の相手でも、そのリプライとリポストにはフォロー外と同じ係数がかかります。
この表の値には1つ注意があります。vm-ranker/params.rs にも重みの既定値が並んでおり、9月29日の変更(クリック0.3など)までは param.rs と同じ値に更新されていました。ところが10月13日以降の変更は反映されず、10月23日時点でもいいね0.5・興味がない-47.52のままです。どちらのファイルも同じ設定キー(rust_home_mixer_favorite_weight など)を読むため、本番では設定システムの値が使われます。READMEはcronによる本番既定値の同期先としてparam.rsを例示していますが、ファイル間に更新の差があるため、vm-ranker側にしか無い0.75倍などの補正値は、本番の値と一致する保証がファイル上はありません。
新規投稿者枠(Author Cold Start)の9月30日の条件変更
新規投稿者枠の条件はauthor_cold_start.rs(コミット07d159b)と param.rs の既定値で読めます。9月17日に投稿経過時間の上限を24時間から48時間へ延ばした直後、9月30日のコミットで枠の性格が変わり、10月23日時点も同じ条件です。
| 条件 | 9月26日時点 | 9月30日以降 |
|---|---|---|
| 投稿者のフォロワー数 | 1,000人以下 | 50,000人以下 |
| ホーム上の表示回数 | 1,000回未満 | 200回未満 |
| 投稿からの経過時間 | 48時間以内 | 2時間以内 |
| 補正前の順位 | 上位約85% | 上位約97% |
| 対象からの選び方 | スコア最上位 | トンプソン抽出 |
リプライとリポストは対象外です。対象から1件を選び、そのスコアが補正前の16番目のスコアを下回る場合に、同じ値まで引き上げます。その後の並べ替えや表示制御で最終位置は変わります。
選び方の変化は読み落とされやすい部分です。以前はモデルのスコアが最も高い1件でした。現在は、候補ごとに「ホーム表示回数のうち、いいねが付いた割合」をベータ分布から1回ずつ引き、引いた値の上位2件のうちスコアが高い方を選びます。事前分布の既定値はα=0.75・β=49.25で、まだ表示が少ない投稿は平均1.5%前後のいいね率を仮定して扱われます。表示が増えるほど実績のいいね率が効く、探索と実績の折衷です。
実務上の読み替えは2つあります。フォロワー1,000人を超えたアカウントも5万人までは枠に入ります。一方で、枠に入れるのは投稿から2時間以内、かつ表示200回未満の間だけです。投稿直後に付いたいいねの割合が、その後の露出の入口を左右する設計です。
通説と公開コードの比較:2023年版の係数と2026年版の違い
「Xアルゴリズム」の解説には、2023年3月に公開された旧Twitter時代のコードの数値が今も混ざっています。2023年4月5日時点の重みはtwitter/the-algorithm-mlのREADME(projects/home/recap)に残っており、リプライ13.5、投稿者が反応したリプライ75.0、通報-369.0でした。2026年版はリポジトリも重みの体系も別物です。
| よく見る通説 | 2026年10月23日のコード |
|---|---|
| リプライはいいねの75倍 | 約7.6倍(相互フォローは約30倍) |
| 通報1件でいいね468件が消える | READMEが誤りと明記 |
| X Premiumはスコアが優遇される | スコア式に加点項目なし |
| 外部リンクは減点される | 減点項目なし(リンク開封+0.2) |
| 画像・動画付きは2倍 | 媒体の加点なし・動画を開く0.02 |
| 保存(ブックマーク)が最も効く | 保存の重みなし |
| ハッシュタグの数で減点 | 個数の減点なし・乱用はスパム |
| 滞在時間は加点されない | 8月25日から滞在0.05が加点 |
「75倍」の出どころは、2023年版で投稿者が反応した返信に付いていた係数75.0です。当時のいいねの係数は0.5だったので、いいね比では150倍でした。「滞在時間は加点されない」は8月13日時点のコードの読みで、8月25日以降は誤りです。日付の古い解説ほど、この種のずれが残っています。
外部リンク付き投稿の評価:直接の減点項目とモデル挙動の区別
外部リンクについて、コードから言えるのは「リンクを理由に減点する重みが無い」ところまでです。リンクを開く行動には0.2の正の重みが付いています。一方、リンク付き投稿でリプライや滞在の予測確率が下がるかどうかは学習済みモデルの挙動で、コードからは判定できません。「リンクを貼ると必ず伸びない」も「影響はゼロ」も、公開コードを根拠には言えないということです。2023年版の解説で見かけた「外部リンクの減点」も、2026年版のparam.rsには対応する項目がありません。
「信頼スコア」とPremium:user-cred-v2が認証を扱う仕組み
Premium(認証)の扱いを確認できる箇所の1つが user-cred-v2 です。フォロー関係と反応にPageRankをかけてアカウントごとのスコアを出すバッチで、ランダムジャンプ(テレポート)先の重みの一部を、認証済みアカウント(青・灰・金の認証、組織、組織所属)に均等に配っています。このスコアは表示制御側が読むラベルの材料になります。コードから読める範囲では、Premiumはおすすめの点数に直接加点されるのではなく、信頼度の計算に入ります。
重みから逆算した投稿設計と、スパム判定を招くので避けるべき運用
同じリプライでも、相互フォローの相手が書いた元投稿なら4倍(5.0に対して20.0)になります。質問で終える、判断が分かれる論点を出すなど、身近な相手が返信したくなる形は重みの構造に合っています。リンクのコピー(20.0)とDM共有(5.0)も大きな正の重みで、手順・一覧・数字のまとめのように人に送りたくなる投稿が当てはまります。10月にいいねが0.66へ上がったので、確率の高い軽い反応を集める投稿の相対的な価値も上がりました。
投稿時刻や曜日を加点する重みは、param.rs にも vm-ranker/params.rs にもありません。時間帯が効くのは間接的で、新規投稿者枠は投稿から2時間以内・表示200回未満のいいね率で候補を選び、候補になれるのは投稿から48時間以内です。フォロワーが実際に開いている時間に投稿する意味は、この2つの時間の上限から来ています。
避けるべきなのは、反応を取りに行く定型の呼びかけです。grox の分類には SpamEngagementBaiting(エンゲージメントの釣り)、SpamEngagementTrading(反応の交換)、SpamHashTagAbuse(ハッシュタグの乱用)があります。「いいねした人全員にフォロー返し」「リプで〇〇配布」のような投稿は、スパムとして表示制御の対象になりうる運用です。相互フォローの重みを狙った相互フォロー募集も同じ理由で勧めません。行動の時系列から不自然な操作を検出する bdsm というモデルも公開されています。
フォロワー数やインプレッションの指標の違いはリーチとは?ビジネス・SNS広告での意味とインプレッションとの違い・リーチ率の計算、広告で表示を買う場合はXのブーストとは?「ブースト済み」の意味・料金・バレるか・取り消せるかを公式規約で解説が参考になります。
自分のアカウントの表示制限をUnder the Hoodで確かめる手順と範囲
8月13日の更新と同時に、Xは「Under the Hood」という透明性ツールを試験提供しています(x.com/i/jf/under_the_hood)。自分のアカウントと投稿に付いた、表示に影響するラベルの集計を確認できます。9月18日からは、法令にもとづく要請で特定の国から投稿が非表示になった場合、その事実と国名も表示されます。READMEは提供範囲を順次広げるとしているため、全アカウントで使えるとは限りません。
ラベルの一部は、悪用を防ぐ目的でコードが非公開です。READMEは、groxで使うLLMのプロンプトと、botmakerのルールの一部を非公開としています。READMEには、異議申し立てで取り消された措置を一定期間かけ直さない abuse-ledger-service も載っています。
param.rsの差分を取り、重み変更をgitとPythonで確認する手順
重みは実験で頻繁に動き、解説記事の日付より、リポジトリの差分を見るほうが確実です。次の手順で、任意の2時点の重みの違いを出せます(Python 3.9以降とgitがあれば動きます)。
git clone --filter=blob:none https://github.com/xai-org/x-algorithm.git
cd x-algorithm
git log --format='%h %ad' --date=short -- home-mixer/params/param.rs | head -3
次のスクリプトを weight_diff.py として保存し、比較したい2つのコミットを渡します。
import re
import subprocess
import sys
PAT = re.compile(r'param!\(\s*(\w+Weight\w*),\s*f64,\s*"[a-z_]+",\s*(-?[0-9.]+)\s*\)')
def weights(rev):
src = subprocess.run(
["git", "show", f"{rev}:home-mixer/params/param.rs"],
capture_output=True, text=True, check=True,
).stdout
return dict(PAT.findall(src))
old, new = weights(sys.argv[1]), weights(sys.argv[2])
for name in sorted(old.keys() | new.keys()):
if old.get(name) != new.get(name):
print(f"{name}: {old.get(name)} -> {new.get(name)}")
重みが初めて公開された8月13日のコミット 47c1bcd と、10月23日のmain(07d159b)を比べると、次の出力になります。2026年10月23日に、Python 3.9.6で実行した結果です。
$ python3 weight_diff.py 47c1bcd 07d159b
ClickWeight: 0.4 -> 0.3
ContClickDwellTimeWeight: 0.0 -> 0.4
ContDwellTimeWeight: 0.004 -> 0.006
DwellWeight: 0.0 -> 0.05
FavoriteWeight: 0.5 -> 0.66
NotInterestedWeight: -43.2 -> -52.272
OonWeightFactor: 0.75 -> None
PostUnexploredWeight: 0.02 -> 0.015
ReactWithVideoWeight: None -> 0.0
TopicOonWeightFactor: 0.5 -> None
VideoCarouselImmersiveVqvWeight: None -> 0.0
VideoCarouselVideoOpenWeight: None -> 1.0
VideoOpenWeight: 0.05 -> 0.02
VqvWeight: 0.05 -> 0.0
10週間で、おすすめ本体の重みは9項目の値が変わり、ReactWithVideoWeight(既定0.0)が新しく加わりました。None は片方に無い項目です。OonWeightFactor と TopicOonWeightFactor は9月24日にvm-rankerへ移ったフォロー外係数、VideoCarousel で始まる2つは動画カルーセル用の別の重みです。VideoOpenWeight は0.05→0.07(8月25日)→0.02(10月13日)と動いており、両端だけを比べると途中の変化は見えません。
このスクリプトは名前に Weight を含む浮動小数の項目しか拾いません。新規投稿者枠のフォロワー上限(ColdStartFollowerCap)や、候補の按分を切り替える EnableFairShareRanking の変更は出力に現れないため、枠や機能の切り替えを追うときは git diff cb45b55 07d159b -- home-mixer/params/param.rs で全体を見てください。
変更の経緯が文書化された例として、docs/BIDIRECTIONAL_BOOST_CHANGE.md があります。相互フォローのリプライ加算は、2026年7月10日に5・10・15・20の値でA/Bテストを始め、7月13日に20で広く適用し、7月24日に15へ下げました。W杯の期間中にフォロー外の話題が見えにくいという声を受けた調整だと、文書に書かれています。
Xの口コミ・レビューを分析するシステムの作り方:収集・判定・集計の3層
ここまでの仕組みは、Xを口コミやレビューの情報源として使う側にも関係します。自社製品の評判を知りたくて「おすすめ」欄を眺めても、表示される投稿は閲覧者ごとの予測確率で並び替えられ、フォロー外は0.75倍、同じ投稿者は減衰し、表示制御で落ちた投稿は見えません。製品名に一致する投稿の傾向を調べるには、おすすめ欄ではなくX APIの検索結果を集めます。ただし、検索語・言語・公開範囲で対象が限られるため、世論全体を代表するデータではありません。
収集層:X APIの直近7日検索を時系列順で取る設定と取得制約
X APIの検索の概要ページによると、/2/tweets/search/recent は直近7日の投稿を対象にし、すべての開発者が使えます。それより古い投稿は全期間検索(/2/tweets/search/all)の対象です。直近検索のAPIリファレンスでは、max_results は10〜100、並び順の sort_order は recency と relevancy の2択です。関連度順はX側の判断が入るため、件数を比べる集計では recency を指定します。
検索式はクエリの組み立てガイドの演算子で書きます。日本語の投稿に絞る lang:ja、リポストを除く -is:retweet、返信を除く -is:reply を付けると、同じ文面の重複がかなり減ります。直近検索のクエリ長は512文字まで(Enterpriseは4,096文字)で、製品名の表記ゆれをORで並べるとこの上限に当たります。レート制限の表では、直近検索はアプリ単位で15分450回、ユーザー単位で15分300回です。
2026年10月23日に再確認した時点でも、APIリファレンスは取得フィールドの指定を post.fields と書き、クエリの組み立てガイドのcurl例は従来の tweet.fields を使っていました。下のコードは既定の応答(投稿IDと本文)だけで動くようにして、この表記の揺れに依存しない形にしています。
判定層と集計層:辞書判定からSQLiteへの保存までのPythonコード
収集・保存の動作を確認する試作には、辞書による肯定・否定の判定を使えます。評判の集計に使う前に、対象製品の投稿を人手で確認して誤判定を評価します。次のコードは、直近検索の結果をページ送りしながらSQLiteへ保存し、ラベルごとの件数を出します。2回目以降は保存済みの最大IDを since_id に渡すため、同じ投稿を二重に読みません。保存の確定は全ページを取り終えた後の1回だけにしてあります。ページごとに確定すると、途中で通信が切れたときに新しい側のページだけが残り、次回の since_id がそれより古い未取得分を飛ばしてしまうためです。
import os
import sqlite3
import time
import requests
URL = "https://api.x.com/2/tweets/search/recent"
QUERY = '("製品名" OR "サービス名") lang:ja -is:retweet -is:reply'
POSITIVE = ["使いやすい", "便利", "助かる", "おすすめ", "満足"]
NEGATIVE = ["使いにくい", "不具合", "遅い", "繋がらない", "解約"]
db = sqlite3.connect("x_reviews.db")
db.execute("CREATE TABLE IF NOT EXISTS posts (id TEXT PRIMARY KEY, text TEXT, label TEXT)")
def label(text):
pos = sum(w in text for w in POSITIVE)
neg = sum(w in text for w in NEGATIVE)
if neg > pos:
return "negative"
if pos > neg:
return "positive"
return "neutral"
def collect():
headers = {"Authorization": f"Bearer {os.environ['BEARER_TOKEN']}"}
params = {"query": QUERY, "max_results": 100, "sort_order": "recency"}
last = db.execute("SELECT MAX(CAST(id AS INTEGER)) FROM posts").fetchone()[0]
if last:
params["since_id"] = str(last)
try:
while True:
res = requests.get(URL, headers=headers, params=params, timeout=10)
if res.status_code == 429:
reset = int(res.headers.get("x-rate-limit-reset", time.time() + 60))
time.sleep(max(reset - time.time(), 1))
continue
res.raise_for_status()
body = res.json()
for post in body.get("data", []):
db.execute("INSERT OR IGNORE INTO posts VALUES (?, ?, ?)",
(post["id"], post["text"], label(post["text"])))
token = body.get("meta", {}).get("next_token")
if not token:
break
params["next_token"] = token
except Exception:
db.rollback()
raise
db.commit()
collect()
for row in db.execute("SELECT label, COUNT(*) FROM posts GROUP BY label"):
print(*row)
コードを x_reviews.py として保存し、python -m pip install requests で依存ライブラリを入れます。BEARER_TOKEN を環境変数に設定し、検索式の「製品名」「サービス名」を対象の名称に置き換えて、python x_reviews.py を実行します。応答の meta.next_token が無くなるまでページを送り、APIが返す検索結果を保存します。初回は直近7日が対象で、次回以降は保存済みIDより新しい投稿が対象です。トークンの発行手順、429の扱い、支出上限の設定はX API(旧Twitter API)の料金と使い方|従量課金の単価・無料クレジット・レート制限【2026年10月】で扱っています。
辞書判定の弱点は、否定表現と皮肉です。「遅いと聞いていたが遅くない」は「遅い」に1点が付き、文全体の否定を解釈できずnegativeになります。誤判定が目立ってきたら、判定層の label() 関数だけを感情分析モデルへ差し替えます。手法の違いと精度の考え方は感情分析とは?仕組み・手法の違いからAI時代の精度と導入判断まで解説、頻出語や共起から論点を拾う方法はテキストマイニングとは?手法・やり方・無料ツールから企業の導入判断まで解説にまとめています。
費用の目安:Post読み取り0.005ドルで決まる月額の試算
X APIの料金ページでは、Post読み取りは1件0.005ドルです。課金はリクエスト単位ではなく返ってきた投稿の件数単位なので、max_results を増やしても1件あたりは変わりません。同じ投稿をUTCの同じ日に読み直した分は、重複として課金されない扱いです(料金ページは「soft guarantee」としています)。
| 想定する規模 | 月の読み取り件数 | 月額の目安 |
|---|---|---|
| 1製品・1日100件 | 約3,000件 | 約15ドル |
| 1製品・1日300件 | 約9,000件 | 約45ドル |
| 複数製品・1日1,000件 | 約30,000件 | 約150ドル |
| 業界全体・1日10,000件 | 約300,000件 | 約1,500ドル |
費用を膨らませるのは、検索式が広すぎて無関係な投稿まで拾うことです。製品名が一般名詞と重なる場合(例えば「ノート」)は、最初の1週間だけ全件を目で見て、除外語を足してから定期実行に移してください。
口コミ分析システムを自前で組むか、既製ツールで済ませるかの判断条件
Xの口コミを社内の別データと突き合わせたいなら自前で組み、画面で傾向を眺められれば足りるなら既製のソーシャルリスニングツールを選びます。判断を分けるのは機能の多さではなく、集めた投稿をどこへ渡すかです。
| 条件 | 自前で組む | 既製ツール |
|---|---|---|
| 問い合わせ履歴・CRMとの結合 | 向く | 連携機能の範囲内 |
| 判定辞書を自社語彙で持つ | 向く | 製品の設定次第 |
| Xと他SNSを横断して見る | 収集先ごとに実装 | 向く |
| 7日より前の過去分が要る | 全期間検索が別途必要 | 製品の保持期間次第 |
| 担当者が画面で眺めるだけ | 過剰 | 向く |
自前で組むのは、否定的な投稿を検知したらチケットを起票する、問い合わせ件数の推移と並べる、といった社内システムへの受け渡しが要件にあり、月の読み取りが数万件以内でAPI費用が月数百ドルに収まり、検索式と判定辞書を保守する担当者を置ける場合です。担当者がいないと、製品名の表記が増えた時点で取りこぼしが静かに増えていきます。
過去1年分の評判を一度だけ調べたい、複数のSNSを1画面で見たい、という要件なら自前の収集基盤は割に合いません。表示制御の判定結果やおすすめでの露出量は外から正確に測れないため、「自社の投稿がどれだけおすすめに出たか」を口コミ分析と同じ基盤で測ろうとするのも避けてください。自社アカウントの指標は、自社データとして別に取ります。
X APIで集めた投稿を社内の顧客データや問い合わせ管理につなぐ設計を、検索式と費用の見積もりから相談したい場合は、API開発・システム連携で受けています。話題の広がり方そのものを読む分析はバズマーケティングとは?「バズる」の意味・基準と手法、分析方法も参考になります。
よくある質問
Xのアルゴリズムは最近いつ変わりましたか?
公開コードは2026年8月13日以降ほぼ毎日更新されています。直近の重みの変更は10月13日と14日で、いいねが0.5から0.66へ、「興味がない」が-47.52から-52.272へ、動画を開く操作が0.07から0.02へ変わりました。10月22日には、候補元ごとの比率を保って候補を間引く処理が有効になっています。最新の状態はGitHubの xai-org/x-algorithm のコミット履歴で確認できます。
Twitterで急に伸びなくなったのはアルゴリズムのせいですか?
候補になる投稿は48時間以内のものに限られ、フォロー外の投稿は0.75倍、同じ投稿者の2件目以降は減衰します。新規投稿者枠は投稿から2時間以内・表示200回未満の間しか効かず、フォロワーが5万人を超えると対象から外れます。9月30日の条件変更で、投稿から2時間を過ぎた投稿や表示が200回に達した投稿は、枠の対象から外れるようになりました。表示制限のラベルが付いていないかはUnder the Hoodで確認できます。
Xで一番伸びる投稿時間や投稿頻度はありますか?
時刻や投稿頻度を加点する重みは、公開コードにありません。効くのは時間の上限で、新規投稿者枠は投稿から2時間以内、候補全体は48時間以内に限られます。フォロワーが開いている時間に投稿すると、この時間内に反応が集まりやすくなります。同じ閲覧者向けの候補に同一投稿者の投稿が複数含まれると、公開コードの既定値では2件目に0.625倍のスコア補正がかかります。この係数は表示回数の倍率ではなく、48時間の制限も公開コードで確認できる候補処理の条件です。
Xの口コミやレビューを自社で集めて分析できますか?
X APIの直近検索(/2/tweets/search/recent)で、直近7日の投稿を製品名などの検索式で集められます。lang:ja と -is:retweet で日本語の投稿からリポストを除き、sort_order=recency で時系列順に取るのが基本です。返信も除く場合は -is:reply を追加します。Post読み取りは1件0.005ドルで、1日300件なら月45ドル前後になります。おすすめ欄の表示は閲覧者ごとに並び替えられているため、評判の分布を測る用途には使えません。
Xのエンゲージメントには何が含まれますか?
アルゴリズム上は、いいね・リプライ・リポスト・引用・共有(DM・リンクコピー含む)がエンゲージメントに分類されています。ほかにクリック(投稿・プロフィール・リンク・画像・動画)、注意(滞在・視聴・クリック後の滞在時間)、フォロー、否定的な反応(興味がない・ミュート・ブロック・通報)を予測しています。重みが最も大きい正の行動は、リンクのコピーによる共有と相互フォローの元投稿へのリプライ(どちらも20.0)です。保存(ブックマーク)は重みの一覧にありません。