Xには、アカウントが投稿したときに知らせてくれる無料のWebhookがありません。よくある代わりの方法はポーリングで、数秒ごとにアカウントの最新ツイートを取得して前回と比べます。1アカウントならこれで足ります。50アカウントになると費用がかさみ、ポーリングの合間に投稿されたツイートを取りこぼすこともあります。
アカウント監視なら逆の流れになります。アカウントを一度登録すれば、新しいツイートが署名付きのPOSTとしてあなたのサーバーに届きます。このガイドでは、最初のアカウントの登録からサーバー停止時の対応まで、Pythonで設定する手順を説明します。
できること
- 規模を問わず、公開されているあらゆるアカウントを監視できます。フォロワー50人のアカウントも、500万人のアカウントと同じ頻度で確認します。
- 新しいツイート1件につき1イベント。シンプル形式(英語)のツイート全体が含まれます。本文、投稿者、各種カウント、メディア、リプライ・引用・リツイートかどうかです。
- 確認間隔はプランに応じて最長60秒、5秒、1秒です。
- イベントは7日間保存されるため、取りこぼした分はpull APIで読み取れます。
| Class | Guarantee | Typical |
|---|---|---|
| Standard | We check at least every 60 s | 15–60 s |
| Fast | We check at least every 5 s | 2–5 s |
| Real-time | We check at least every 1 s | 0.5–1 s |
この間隔は当社が確認する頻度です。X側でも新しいツイートがタイムラインに表示されるまで少し時間がかかり、その遅れが加わります。各イベントにはtweetCreatedAtとdetectedAtが含まれるので、実際の遅延を測れます。
ステップ1:APIキーとプランを用意する
こちらでアカウントを作成し、ダッシュボードからキーをコピーします。次に、Monitorsでプランを申し込みます。月額料金は前払い残高から差し引かれ、/monitors/*へのコールはリクエストごとには課金されません。
| Accounts | Standard (60 s) | Fast (5 s) | Real-time (1 s) |
|---|---|---|---|
| 10 | $5 | $9 | $19 |
| 50 | $15 | $29 | $59 |
| 250 | $49 | $99 | $199 |
| 1,000 | $149 | $299 | $599 |
| 5,000 | $499 | $999 | $1,999 |
最小のプランは10アカウントで月$5です。キーは環境変数に保存しておきます。
export TWITTRAPI_API_KEY="your-key"ステップ2:監視するアカウントを追加する
1リクエストで最大100件のユーザー名またはユーザーIDを送れます。
import os
import requests
API = "https://api.twittrapi.com"
HEADERS = {"X-API-KEY": os.environ["TWITTRAPI_API_KEY"]}
r = requests.post(
f"{API}/monitors/accounts",
headers=HEADERS,
json={"usernames": ["XDevelopers", "NASA", "OpenAI"]},
timeout=30,
)
r.raise_for_status()
for result in r.json()["data"]:
print(result["input"], result.get("status") or result.get("error"))アカウントごとに結果が返ります。added、already_watching、または「見つからない」「鍵アカウント」などのエラーです。鍵アカウントは監視できません。配信されるのは監視開始後の最初のツイートからで、それより前のツイートは送られません。過去のツイートはユーザーのツイート取得エンドポイント(英語)で取得してください。
ステップ3:Webhookを設定する
URLは公開されていて、httpsである必要があります。プライベートアドレスやローカルアドレスは拒否され、リダイレクトはたどりません。
r = requests.put(
f"{API}/monitors/webhook",
headers=HEADERS,
json={"url": "https://example.com/hooks/twittrapi"},
timeout=30,
)
r.raise_for_status()
print(r.json()["webhook"]["secret"]) # whsec_...最初の呼び出しで、whsec_で始まる署名用シークレットが返ります。サーバーにTWITTRAPI_WEBHOOK_SECRETとして保存してください。あとでURLを変更しても、シークレットは変わりません。
手元のPCでテストするときは、ngrokやCloudflare Tunnelなどのトンネルでローカルのポートを公開し、そのhttpsアドレスをWebhookのURLに使います。
ステップ4:イベントを受信して署名を検証する
新しいツイートごとに、JSONボディを持つPOSTが1回届きます。X-TwittrAPI-Signatureヘッダーには、タイムスタンプと、<timestamp>.<raw body>をシークレットで計算したHMAC-SHA256が入っています。JSONをパースする前に生のバイト列で検証し、古いタイムスタンプは拒否してください。こうすれば、盗まれたリクエストを再送されても通りません。
import hashlib
import hmac
import os
import time
from flask import Flask, abort, request
SECRET = os.environ["TWITTRAPI_WEBHOOK_SECRET"].encode()
app = Flask(__name__)
def verify(header: str, raw_body: bytes, tolerance: int = 300) -> bool:
parts = dict(p.strip().split("=", 1) for p in header.split(",") if "=" in p)
t, sig = parts.get("t", ""), parts.get("v1", "")
if not t.isdigit() or not sig or abs(time.time() - int(t)) > tolerance:
return False
expected = hmac.new(SECRET, t.encode() + b"." + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig)
@app.post("/hooks/twittrapi")
def hook():
if not verify(request.headers.get("X-TwittrAPI-Signature", ""), request.get_data()):
abort(401)
event = request.get_json()
if event["event"] == "tweet":
tweet = event["tweet"]
print(tweet["author"]["username"], tweet["url"], tweet["text"][:80])
return "", 2045秒以内に2xxのいずれかを返してください。表示するだけでなく重い処理をするなら、イベントをキューに入れて先に応答します。同じハンドラーのNode.js版とGo版は監視のドキュメント(英語)にあります。
ツイートイベントは次のような形です。
{
"event": "tweet",
"id": "1849203",
"monitoredUserId": "2244994945",
"tweetId": "2019881223666233717",
"tweetCreatedAt": "2026-02-06T21:09:45Z",
"detectedAt": "2026-02-06T21:09:46.212Z",
"tweet": {
"id": "2019881223666233717",
"url": "https://x.com/XDevelopers/status/2019881223666233717",
"text": "Officially launching X API Pay-Per-Use …",
"author": { "id": "2244994945", "username": "XDevelopers" },
"replyTo": null,
"quoted": null,
"retweetOf": null
}
}リプライとリツイートも含まれます。オリジナルの投稿だけが必要なら、replyToかretweetOfが設定されたイベントを読み飛ばしてください。
ステップ5:テストイベントを送る
実際のツイートを待つ前に、エンドポイントが時間内に応答するか確認します。
r = requests.post(f"{API}/monitors/webhook/test", headers=HEADERS, timeout=30)
print(r.json()) # {"ok": true, "statusCode": 204, "latencyMs": 84}テストイベントは本物と同じように署名され、X-TwittrAPI-Event: testヘッダーが付きます。
ステップ6:停止中に取りこぼしたイベントを取得する
サーバーが止まっている間、失敗した配信は間隔を広げながら最大24時間リトライされます。20回連続で失敗するとWebhookは無効になり、メールでお知らせします。監視自体は続きます。イベントは7日間、pull APIで読み取れます。
since = None # store the last nextSince somewhere durable
while True:
params = {"limit": 500}
if since:
params["since"] = since
page = requests.get(f"{API}/monitors/events", headers=HEADERS, params=params, timeout=30).json()
for event in page["data"]:
print(event["tweet"]["url"])
since = page["nextSince"] or since
if not page["hasMore"]:
breakリトライは順不同で届くことがあり、まれに2回届きます。重複はX-TwittrAPI-Deliveryヘッダーで除き、並べ替えにはtweetCreatedAtを使ってください。エンドポイントが復旧したら、もう一度PUT /monitors/webhookを送るとWebhookが再び有効になります。
Webhookとポーリング、どちらを使うか
| タイムラインのポーリング | アカウント監視 | |
|---|---|---|
| 費用 | ポーリング1回・1アカウントごとに課金コール1回 | プランごとの月額定額 |
| 遅延 | ポーリングの間隔 | 60秒、5秒、1秒 |
| 自分で用意するもの | スケジューラー、状態管理、重複除去 | エンドポイント1つ |
| 取りこぼし | ポーリングの合間に起こりうる | 7日間保存、あとから取得可能 |
数アカウントを数分おきに確認するだけなら、ポーリングで十分です。1アカウントを5秒ごとに確認すると月に約518,000コールになり、50アカウントのFastプラン($29)より高くつきます。監視の対象外であるキーワードやハッシュタグは、since_idを付けて検索(英語)をポーリングすれば、毎回新しいツイートだけが返ります。
よくある質問
Xには新着ツイートを受け取るWebhookがありますか?
あります。Activity APIで、イベントごとに課金されます。定額の監視プランとの比較は新着ポスト向けX API Webhook(英語)をご覧ください。Xには無料の選択肢はありません。
フォロワーの少ないアカウントも監視できますか?
できます。フォロワー数の下限はありません。プランに登録した公開アカウントは、すべてプランの間隔で確認されます。
削除されたツイートは通知されますか?
されません。イベントはツイートを検知したときに送られます。削除で別のイベントが作られることはありません。
残高がなくなるとどうなりますか?
更新時にプランが一時停止します。監視中のアカウントはそのまま残りますが、チャージしてプランを更新するまでイベントは作られません。
出典
- アカウント監視のドキュメント(英語)(API、イベント、署名、リトライ、制限)
- シンプル形式:ツイートのフィールド(英語)
- Twitter Streaming APIの代替(英語)
TwittrAPIはX Corp.とは提携していません。公開データのみを読み取ります。




