TwexAPI で X の有料プロモーションを検出する方法
自然に広がった投稿と有料プロモーションは、タイムライン上では似て見えることがあります。市場調査、キャンペーンレビュー、競合モニタリングでは、この違いを分けることが重要です。ユーザーの共有で広がった投稿と、有料配信で露出した投稿を同じ指標として解釈すべきではありません。
TwexAPI はツイートオブジェクトに is_paid_promotion フィールドを返します。POST /twitter/tweets/lookup と組み合わせると、tweet ID のリストを確認し、どの投稿が有料プロモーションとしてマークされたかをラベル付けし、raw レスポンス、候補ソース、エンゲージメント指標を一緒に保存できます。
このフィールドが重要な理由
このフィールドが重要な理由 は、コンテンツの成果を有料露出と自然な議論に分けられることです。手動のタイムライン確認では、もう表示されていないプロモーション投稿を見落とす可能性があります。バッチ lookup なら判断を安定したデータフローに入れられます。
- 有料プロモーションラベル:
is_paid_promotion === trueの場合、その投稿を有料プロモーションサンプルとして扱う。 - バッチ処理:候補 tweet ID を配列で送信し、複数のツイートオブジェクトを取得する。
- 証拠保存:raw JSON、候補ソース、取得時刻、エンゲージメント指標を保存し、後で判断を説明できるようにする。
- 調査ループ:Advanced Search、キャンペーンリスト、手動サンプルで候補 ID を集め、lookup でプロモーションマーカーを確認する。
注意:false またはフィールド欠落を「有料配信が絶対にない」と書くべきではありません。より安全なラベルは「このレスポンスでは有料マークが返らなかった」です。これにより、プラットフォーム上の可視性、サンプル偏り、フィールド欠落を確定結論と誤読しにくくなります。
技術実装:バッチラベル付け
バッチラベル付け とは、tweet ID 配列を POST /twitter/tweets/lookup に送信し、レスポンス data 内の各ツイートオブジェクトから is_paid_promotion を読むことです。このフローはすべての広告を発見するものではありません。すでに集めた候補 tweet ID に監査可能なラベルを付けるものです。
1import requests
2from datetime import datetime, timezone
3
4API_URL = "https://api.twexapi.io/twitter/tweets/lookup"
5TOKEN = "YOUR_TWEXAPI_BEARER_TOKEN"
6
7def clean_tweet_ids(tweet_ids):
8 cleaned = []
9 seen = set()
10
11 for value in tweet_ids:
12 tweet_id = str(value).strip()
13 if not tweet_id or tweet_id in seen:
14 continue
15 cleaned.append(tweet_id)
16 seen.add(tweet_id)
17
18 return cleaned
19
20def lookup_tweets(tweet_ids):
21 cleaned_ids = clean_tweet_ids(tweet_ids)
22 if not cleaned_ids:
23 return []
24
25 response = requests.post(
26 API_URL,
27 headers={
28 "Authorization": f"Bearer {TOKEN}",
29 "Content-Type": "application/json",
30 "Accept": "application/json",
31 },
32 json=cleaned_ids,
33 timeout=30,
34 )
35 response.raise_for_status()
36 payload = response.json()
37
38 if payload.get("code", 200) >= 400:
39 raise RuntimeError(payload.get("msg", "TwexAPI returned an error"))
40
41 return payload.get("data") or []
42
43def classify_paid_promotions(tweet_ids, candidate_source):
44 fetched_at = datetime.now(timezone.utc).isoformat()
45 rows = []
46
47 for tweet in lookup_tweets(tweet_ids):
48 if not tweet:
49 continue
50
51 text = tweet.get("full_text") or tweet.get("text") or ""
52 user = tweet.get("user") or {}
53 is_paid = tweet.get("is_paid_promotion") is True
54
55 rows.append({
56 "tweet_id": tweet.get("tweet_id") or tweet.get("id"),
57 "is_paid_promotion": is_paid,
58 "promotion_label": "paid" if is_paid else "not_marked_paid",
59 "candidate_source": candidate_source,
60 "screen_name": user.get("screen_name"),
61 "created_at_datetime": tweet.get("created_at_datetime"),
62 "favorite_count": tweet.get("favorite_count"),
63 "retweet_count": tweet.get("retweet_count"),
64 "reply_count": tweet.get("reply_count"),
65 "view_count": tweet.get("view_count"),
66 "text_preview": text[:160],
67 "fetched_at": fetched_at,
68 "raw": tweet,
69 })
70
71 return rows
72
73candidate_ids = ["123456789", "987654321", "555666777"]
74results = classify_paid_promotions(candidate_ids, candidate_source="competitor_launch_search")
75
76paid_rows = [row for row in results if row["is_paid_promotion"]]
77print(f"Checked {len(results)} tweets; paid promotion marked: {len(paid_rows)}")候補 ID の集め方
候補 ID の集め方 とは、どのツイートを lookup に入れるかを決めることです。すでに大きく伸びた投稿だけを集めると、高エンゲージメント投稿に偏ったサンプルになります。
よくある候補ソース:
- Advanced Search:競合アカウント、ブランド語、キャンペーン hashtag、URL ドメインで候補投稿を集める。
- ランディングページログ:流入元の X 投稿 URL を tweet ID に変換する。
- 手動サンプル:調査担当者が疑わしいプロモーション投稿を候補リストへ追加する。
- 過去キャンペーンリスト:過去の tweet ID を遡ってラベル付けし、自然拡散と有料増幅を分ける。
Advanced Search で候補を集める場合は、クエリ、sortBy、収集時刻、元 tweet ID を一緒に保存します。後でサンプル偏りに気づいた場合、候補ソースに戻って調整できます。
市場調査ワークフロー
市場調査ワークフロー とは、is_paid_promotion を単独の分析結果ではなくラベルとして扱うことです。
- 有料/自然の比率:競合アカウント、キャンペーン hashtag、製品キーワードごとに、有料マーク付き投稿の割合を見る。
- クリエイティブ比較:有料プロモーションと確認されたサンプル内で、動画、画像、スレッド、リンク投稿の成果を比較する。
- 配信タイミング分析:時間帯、曜日、キャンペーン段階ごとにプロモーション投稿の出現を確認する。
- キャンペーンレビュー:自然に伸びた投稿と有料で増幅された投稿を分け、クリエイティブ品質を誤判定しない。
単一の boolean フィールドを予算推定として扱わないでください。これは「プロモーションとしてマークされたか」の証拠であり、投稿時刻、エンゲージメント、形式、遷移先、キャンペーン段階と一緒に分析します。
保存すべきフィールド
保存すべきフィールド とは、有料または未マークの判断を後から説明するための最小証拠です。
| フィールド | 用途 |
|---|---|
tweet_id | 重複排除と再確認 |
is_paid_promotion | 有料プロモーションマーカーが返ったか |
promotion_label | paid、not_marked_paid、missing などの分析状態 |
candidate_source | 投稿がデータセットに入った理由 |
created_at_datetime と fetched_at | 配信時刻と取得時刻の確認 |
user.screen_name | アカウント単位の集計 |
text、urls、media | クリエイティブと遷移先分析 |
favorite_count、retweet_count、reply_count、view_count | 成果比較 |
| raw JSON | フィールドやルール変更後の再処理 |
よくある誤読
よくある誤読 とは、フィールドを過度に解釈したり、サンプル収集の偏りを市場結論として扱うことです。
is_paid_promotion === trueは有料プロモーションの証拠として使えるが、falseや欠落は「このレスポンスではマーカーが返らなかった」という意味にとどまる。- 候補 ID のソースは結論に影響する。高エンゲージメント投稿だけを集めると、有料プロモーションの影響を過大評価しやすい。
- エンゲージメントは直接予算を意味しない。view、like、repost はクリエイティブ、受け手、時間帯、自然な議論にも左右される。
まとめ
まとめ とは、有料プロモーション検出を繰り返せるラベル付けフローにすることです。候補 tweet ID を集め、/twitter/tweets/lookup を呼び、is_paid_promotion を読み、raw レスポンス、候補ソース、エンゲージメント指標を保存します。これにより、競合モニタリング、キャンペーンレビュー、クリエイティブ分析で、有料プロモーションサンプルと自然な議論を分けて見られます。