TwitterデータをGoogleスプレッドシートにエクスポートする方法
Googleスプレッドシートは単体ではTwitterのデータを取得できません。そのため、ツイートやフォロワーは、Apps Scriptからタイマーで呼び出すAPIを経由してシートに入ります。1つのスプレッドシートには最大2,000万セル、ツイートにして約200万件を保存できます。
要点: シートへ取り込むどの方法も、JSONを返すAPIの上で動きます。公式X APIは1投稿あたり$0.005、1フォロワーあたり$0.010の課金で、開発者アプリも必要です。Googleスプレッドシートには、Apps ScriptからSorsa APIを使うのが向いています。ApiKey ヘッダー1つで、1リクエストあたりツイート20件またはフォロワー200件を取得でき、フォロワーは1,000人あたり$0.007から、始めるための100リクエストは無料です。
- エンドポイント
POST /search-tweets- 1ページの件数
- 1リクエストあたりツイート20件
- 料金
- 1,000ツイートあたり$0.07から
#TwitterデータをGoogleスプレッドシートに取り込む仕組み
TwitterのデータをGoogleスプレッドシートに取り込む方法は4つあり、どれもJSONを返すデータソースが必要です。タイマーでAPIを呼び出すApps Script、シート内からヘッダーつきのURLを送るコネクタ系アドオン、Google Sheetsのステップを持つn8n、Make、Zapierなどの自動化ツール、そしてダウンロードしたCSVファイルをファイル > インポートで取り込む方法です。1回限りのファイルなら、無料のTwitterのツイートをCSVにエクスポートツールがCSVを作成します。
数式は5つ目の方法には数えません。IMPORTXML と IMPORTHTML が読み取れるのは1つのWebページだけです。x.comは、ログインしていない訪問者にフォロワーリストも検索結果も表示しないため、数式にはたどるページがなく、x.comのレイアウトが変わるたびに動かなくなります。
| 方法 | 事前の準備 | 自動更新 | 結果のページ送り |
|---|---|---|---|
| Apps Script(本ガイド) | スクリプトを1度貼り付けるだけ | あり(時間主導型トリガー) | あり、何ページでも |
| コネクタ系アドオン | アドオンのフォームにURLとヘッダーを入力 | あり(アドオンのスケジュール) | アドオン次第 |
| n8n、Make、Zapier | Google Sheetsのステップを持つシナリオ | あり | あり(ループを使用) |
| CSVファイル | ダウンロードして、ファイル > インポート | なし | ツールが実行 |
Apps Script(本ガイド)
- 事前の準備
- スクリプトを1度貼り付けるだけ
- 自動更新
- あり(時間主導型トリガー)
- 結果のページ送り
- あり、何ページでも
コネクタ系アドオン
- 事前の準備
- アドオンのフォームにURLとヘッダーを入力
- 自動更新
- あり(アドオンのスケジュール)
- 結果のページ送り
- アドオン次第
n8n、Make、Zapier
- 事前の準備
- Google Sheetsのステップを持つシナリオ
- 自動更新
- あり
- 結果のページ送り
- あり(ループを使用)
CSVファイル
- 事前の準備
- ダウンロードして、ファイル > インポート
- 自動更新
- なし
- 結果のページ送り
- ツールが実行
コストと手間を左右するのはデータソースです。公式X APIには、開発者アカウント、アプリ、OAuthが必要です。従量課金プランの料金は、Xの料金ページ(新しいタブで開きます)によると、投稿の読み取りが1件$0.005、フォロワーまたはプロフィールが1件$0.010で、投稿の読み取りは月300万件が上限です。2026年11月22日からは、投稿と一緒に返される投稿者のプロフィールにも$0.010が課金されるため、投稿とその投稿者で$0.015になります(Xの10月23日付の告知(新しいタブで開きます))。スプレッドシートに限らず、Xの公開データを取得するあらゆる方法は、Twitterをスクレイピングする方法のガイドで比較しています。
#Sorsa APIでツイートをGoogleスプレッドシートに取り込む
Twitter(X)API兼スクレイピングツールであるSorsa APIは、ApiKey ヘッダーが1つ付いたHTTPリクエストであれば応答します。これは、Apps Scriptの UrlFetchApp が必要とするすべてです。ツイート、フォロワー、プロフィールをGoogleスプレッドシートに取り込むなら、Sorsa APIが向いています。1リクエストでツイート20件またはフォロワー200件、2006年まで遡る検索、全プランで毎秒20リクエストに対応し、Xの開発者アカウントもOAuthアプリもXログインも不要です。
下のスクリプトは、スプレッドシートに「X data」メニューを追加します。検索に合致する新しい投稿の取り込み、アカウントのフォロワーリスト全体のエクスポート、=X_PROFILES() 数式の提供ができます。セットアップは6ステップです。
-
APIキーを取得します。 サインアップして、ダッシュボードからキーをコピーします。最初の100リクエストは無料で、カードは不要、有効期限もありません。
-
スクリプトエディタを開きます。 スプレッドシートで、拡張機能 > Apps Scriptを選びます。このシートに紐づいたプロジェクトが開きます。
-
スクリプトを貼り付けます。
Code.gsの内容をすべて下のコードに置き換え、SEARCHに検索クエリを、ACCOUNTにフォロワーを取得したいハンドルを設定します。クエリにはXの検索演算子をすべて使えます。一覧はTwitter検索演算子にあります。Code.gs // Twitter (X) data to Google Sheets with Sorsa API. // Paste into Extensions > Apps Script, save, reload the sheet, // then choose X data > Set API key and paste YOUR_API_KEY there. const API = 'https://api.sorsa.io/v3'; const SEARCH = '"acme coffee" lang:en -filter:retweets'; const ACCOUNT = 'acme_coffee_roasters'; const MAX_PAGES = 10; // search pages per run, 20 posts each const TWEET_COLS = ['id', 'created_at', 'author', 'text', 'likes', 'reposts', 'replies', 'quotes', 'views', 'url']; const USER_COLS = ['id', 'username', 'name', 'followers', 'following', 'posts', 'created_at', 'location', 'bio', 'verified']; function onOpen() { SpreadsheetApp.getUi().createMenu('X data') .addItem('Set API key', 'setApiKey') .addItem('Import new search results', 'importSearch') .addItem('Export followers', 'exportFollowers') .addToUi(); } function setApiKey() { const ui = SpreadsheetApp.getUi(); const answer = ui.prompt('Paste your Sorsa API key'); if (answer.getSelectedButton() !== ui.Button.OK) return; PropertiesService.getUserProperties() .setProperty('SORSA_API_KEY', answer.getResponseText().trim()); } // One request: GET params go in the URL, POST params in a JSON body. function sorsa_(method, path, params) { const key = PropertiesService.getUserProperties() .getProperty('SORSA_API_KEY'); if (!key) throw new Error('Run X data > Set API key first.'); const options = { method: method, headers: { ApiKey: key }, muteHttpExceptions: true }; let url = API + path; if (method === 'get') { url += '?' + Object.keys(params).map((k) => [].concat(params[k]) .map((v) => k + '=' + encodeURIComponent(v)).join('&')).join('&'); } else { options.contentType = 'application/json'; options.payload = JSON.stringify(params); } for (let attempt = 1; attempt <= 3; attempt++) { const res = UrlFetchApp.fetch(url, options); const code = res.getResponseCode(); if (code === 200) return JSON.parse(res.getContentText()); if (code !== 429) throw new Error(code + ' ' + res.getContentText()); Utilities.sleep(1000 * attempt); // over 20 requests a second } throw new Error('429 three times in a row'); } function sheet_(name, cols) { const book = SpreadsheetApp.getActiveSpreadsheet(); const sh = book.getSheetByName(name) || book.insertSheet(name); if (sh.getLastRow() === 0) { sh.getRange('A:A').setNumberFormat('@'); // 19-digit IDs stay text sh.appendRow(cols); sh.setFrozenRows(1); } return sh; } function append_(sh, rows) { if (!rows.length) return; sh.getRange(sh.getLastRow() + 1, 1, rows.length, rows[0].length) .setValues(rows); } // Text that starts with = + or - would be read as a formula. function safe_(s) { s = s || ''; return /^[=+-]/.test(s) ? "'" + s : s; } function tweetRow_(t) { const u = t.user || {}; return [t.id, new Date(t.created_at), '@' + u.username, safe_(t.full_text), t.likes_count || 0, t.retweet_count || 0, t.reply_count || 0, t.quote_count || 0, t.view_count || 0, 'https://x.com/' + u.username + '/status/' + t.id]; } function userRow_(u) { return [u.id, u.username, safe_(u.display_name), u.followers_count, u.followings_count, u.tweets_count, new Date(u.created_at), safe_(u.location), safe_(u.description), u.verified]; } // New posts for SEARCH, newest first, until the first ID already in // the sheet. They are appended oldest first, so the sheet reads as a log. function importSearch() { const sh = sheet_('Search', TWEET_COLS); const last = sh.getLastRow(); const seen = new Set(last > 1 ? sh.getRange(2, 1, last - 1, 1).getDisplayValues().flat() : []); const rows = []; let cursor = null; pages: for (let page = 0; page < MAX_PAGES; page++) { const body = { query: SEARCH, order: 'latest' }; if (cursor) body.next_cursor = cursor; const res = sorsa_('post', '/search-tweets', body); for (const t of res.tweets || []) { if (seen.has(t.id)) break pages; seen.add(t.id); rows.push(tweetRow_(t)); } cursor = res.next_cursor; if (!cursor) break; } append_(sh, rows.reverse()); } // Every follower of ACCOUNT, 200 per request. Each run stops after five // minutes, under the six-minute limit, and the next run resumes from // the saved cursor. Delete FOLLOWERS_CURSOR to start a new export. function exportFollowers() { const props = PropertiesService.getUserProperties(); let cursor = props.getProperty('FOLLOWERS_CURSOR'); if (cursor === 'done') return; const sh = sheet_('Followers', USER_COLS); const stopAt = Date.now() + 5 * 60 * 1000; while (Date.now() < stopAt) { const params = { username: ACCOUNT }; if (cursor) params.next_cursor = cursor; const res = sorsa_('get', '/followers', params); append_(sh, (res.users || []).map(userRow_)); cursor = res.next_cursor; props.setProperty('FOLLOWERS_CURSOR', cursor || 'done'); if (!cursor) return; } } /** * Profiles for up to 100 handles from one request: =X_PROFILES(A2:A101) * @param {string[][]} handles A column of X handles, with or without @. * @return {Array[]} One row per handle, in the same order. * @customfunction */ function X_PROFILES(handles) { const names = [].concat(handles).flat() .map((h) => String(h).trim().replace(/^@/, '')).slice(0, 100); const ask = names.filter((h) => h); if (!ask.length) return ''; const res = sorsa_('get', '/info-batch', { usernames: ask }); const found = {}; for (const u of res.users || []) found[u.username.toLowerCase()] = u; const blank = USER_COLS.map(() => ''); return names.map((h) => found[h.toLowerCase()] ? userRow_(found[h.toLowerCase()]) : blank); } // Run once: search every hour, followers every 10 minutes until done. function createTriggers() { ScriptApp.getProjectTriggers().forEach((t) => ScriptApp.deleteTrigger(t)); ScriptApp.newTrigger('importSearch').timeBased().everyHours(1).create(); ScriptApp.newTrigger('exportFollowers').timeBased().everyMinutes(10) .create(); } -
保存して、シートを再読み込みします。 Ctrl+S(MacはCmd+S)を押してエディタを閉じ、スプレッドシートのタブを再読み込みします。ヘルプの隣に「X data」メニューが表示されます。
-
キーを保存します。 X data > Set API keyを選び、キーを貼り付けます。スクリプトはキーをユーザープロパティに保存するので、セルにも、コードにも、共有するシートのコピーにも残りません。
-
最初のインポートを実行します。 X data > Import new search resultsを選び、Googleが求める2つの権限(このスプレッドシートへのアクセスと、外部サービスへの接続)を許可します。Searchタブが作られ、古い順に最大200件の投稿が入ります。
ヘッダー1つ、ページごとにリクエスト1回、書き込み1回。パイプライン全体がスプレッドシートの中で完結します。
スクリプトの検索は、order を latest に設定して POST /search-tweets(新しいタブで開きます) を呼び出します。各レスポンスには最大20件の投稿が含まれ、どの投稿にも投稿者のプロフィール全体が付き、次ページ用の next_cursor も返ります。カーソルとは、次の結果ページを指すトークンのことで、最後のページではカーソルが返りません。検索ではなく、1つのアカウントの投稿でシートを埋めたい場合は、本文に username を入れて POST /user-tweets(新しいタブで開きます) を呼び出します。このエンドポイントはユーザーの全ツイートをダウンロードのガイドで詳しく解説しています。
{
"tweets": [
{
"id": "2116630142857191424",
"full_text": "Our Ethiopia natural roast is back on the menu.",
"created_at": "2026-11-01T14:03:00Z",
"lang": "en",
"likes_count": 42,
"retweet_count": 5,
"reply_count": 3,
"quote_count": 1,
"view_count": 3810,
"bookmark_count": 2,
"user": {
"id": "1500000000000000004",
"username": "acme_coffee_roasters",
"display_name": "Acme Coffee Roasters",
"followers_count": 12840
}
}
],
"next_cursor": "DAACCgACG3eLqJBAJxAKAAMbd4uokD-nGAgABAAAAAIAAA"
}
#各列に入るデータ
各投稿は10列の1行になり、そのうち3列は、JSONをそのままコピーしただけでは壊れてしまうため、注意が必要です。表は、各列とレスポンス内のフィールドの対応を示します。
| 列 | レスポンス内のフィールド | スクリプトの処理 |
|---|---|---|
| id | id | プレーンテキストに設定した列に書き込む |
| created_at | created_at | ISO 8601の文字列を本物の日付に変換する |
| author | user.username | @を付ける |
| text | full_text | 先頭が =、+、- の場合は、前にアポストロフィを付ける |
| likes, reposts, replies, quotes, views | likes_count, retweet_count, reply_count, quote_count, view_count | 値がない場合は0を書き込む |
| url | user.username と id から組み立て | x.com上の投稿へのリンク |
id
- レスポンス内のフィールド
id- スクリプトの処理
- プレーンテキストに設定した列に書き込む
created_at
- レスポンス内のフィールド
created_at- スクリプトの処理
- ISO 8601の文字列を本物の日付に変換する
author
- レスポンス内のフィールド
user.username- スクリプトの処理
- @を付ける
text
- レスポンス内のフィールド
full_text- スクリプトの処理
- 先頭が =、+、- の場合は、前にアポストロフィを付ける
likes, reposts, replies, quotes, views
- レスポンス内のフィールド
likes_count,retweet_count,reply_count,quote_count,view_count- スクリプトの処理
- 値がない場合は0を書き込む
url
- レスポンス内のフィールド
user.usernameとidから組み立て- スクリプトの処理
- x.com上の投稿へのリンク
シートが壊れる原因として知られている3つの落とし穴は次のとおりです。
- ツイートIDは数値にすると桁が欠けます。 Xの投稿IDは19桁ですが、Googleスプレッドシートが保持する有効桁数は15桁なので、数値セルでは下4桁が0になり、IDが投稿を指さなくなります。スクリプトは、最初の行を書き込む前にA列をプレーンテキストに設定します。
- 投稿テキストが数式に見えることがあります。 「=」「+」「-」で始まる投稿は、スプレッドシートが数式と解釈してエラーを表示します。スクリプトは先頭にアポストロフィを付けます。アポストロフィは表示されず、テキストはテキストのまま保たれます。
- 日付は日付として並べ替えられるようにします。 APIは
created_atをISO 8601で返すので、new Date()でそのまま読み取れ、列は日付として並べ替え、フィルタ、グラフ化ができます。
重複がシートに入ることはありません。スクリプトは検索のたびに、A列にあるIDを読み込み、最新の投稿から順に取得して、すでに保存済みの最初の投稿で停止します。新しい投稿がなかった実行は、リクエスト1回分で済みます。
#スケジュールでシートを更新し続ける
時間主導型トリガーはインポートを自動で実行します。createTriggers() を実行すると、検索を1時間ごと、フォロワーのエクスポートを完了するまで10分ごとという2つが一度に設定されます。スクリプトエディタを開き、関数リストから createTriggers を選んで、1回だけ実行してください。Googleは、シートが開いているかどうかに関係なく、自分のキーを使い、自分のアカウントとして関数を実行します。
新しい投稿が1ページ分見つかる1時間ごとの検索は、月に720リクエストを使います。Starterプランの10,000リクエストの7%です。Apps Script自体は無料で、1時間ごとの実行は、無料のGoogleアカウントの制限に十分収まります。スクリプトの設計に関わるGoogleのApps Script割り当てのページ(新しいタブで開きます)の制限は次のとおりです。
| 制限 | 無料のGoogleアカウント | Google Workspace |
|---|---|---|
| 1日のURL Fetch呼び出し回数 | 2万 | 10万 |
| 1回の実行時間 | 6分 | 6分 |
| 1日のトリガー実行時間 | 90分 | 6時間 |
| カスタム関数の実行時間 | 30秒 | 30秒 |
1日のURL Fetch呼び出し回数
- 無料のGoogleアカウント
- 2万
- Google Workspace
- 10万
1回の実行時間
- 無料のGoogleアカウント
- 6分
- Google Workspace
- 6分
1日のトリガー実行時間
- 無料のGoogleアカウント
- 90分
- Google Workspace
- 6時間
カスタム関数の実行時間
- 無料のGoogleアカウント
- 30秒
- Google Workspace
- 30秒
時間主導型トリガーは、1、5、10、15、30分ごと、または指定した時刻に1日1回の間隔でも実行できます。トリガーによる実行が失敗すると、Googleがスクリプトの発生させたエラーを添えてメールで知らせます。
知っておきたいこと
検索は
MAX_PAGESページ、デフォルトでは200件の投稿で止まります。トラフィックの多いクエリで、2回の実行の間に新しい投稿が200件を超えた場合、古いものから順に取りこぼされます。ブランド名やアクセスの多いハッシュタグでは、MAX_PAGESを増やすか、トリガーの実行間隔を短くしてください。
#フォロワーリスト全体をGoogleスプレッドシートにエクスポートする
アカウントの全フォロワーをGoogleスプレッドシートにエクスポートするには、GET /followers(新しいタブで開きます) を200プロフィールずつ順に呼び出し、各ページを追記します。フォロワー1万人のリストなら50リクエストです。X data > Export followersを選ぶと、スクリプトが、各フォロワーのID、ハンドル、名前、フォロワー数とフォロー数、投稿数、登録日、所在地、プロフィール文、認証済みフラグをFollowersタブに書き込みます。
長いリストは1回の実行では収まらないため、スクリプトはそれを前提に作られています。Apps Scriptは実行を6分で停止するので、exportFollowers() は5分間動作してからカーソルをユーザープロパティに保存して終了します。次の実行は、メニューからでも10分ごとのトリガーからでも、そのカーソルから再開します。カーソルのないページを受け取った実行が、エクスポートの完了を記録します。フォロワー30万人のリストは200件のページ1,500枚で、必要な回数の実行にわたってタブが埋まっていき、同じページを2度取得することはありません。
価格差が最も大きいのがフォロワーです。公式X APIは返したフォロワー1人につき$0.010を課金するので、10万人のリストは$1,000かかります。Sorsa APIなら同じリストを$0.70から、フォロワー1,000人あたり$0.007から取得できます。無料の100リクエストで、最初の2万フォロワーをカバーできます。フォロワーリストをシートではなくCSVやExcelファイルとして保存するには、Twitterフォロワーのエクスポートをご覧ください。
#1つの数式でプロフィール表を作る
=X_PROFILES(A2:A101) は、最大100件のハンドルの列を、1リクエストでプロフィールの表に変えます。A列にハンドルを入力し(@の有無は問いません)、B2に数式を入れると、行はハンドルごとに、同じ順序で右と下に展開されます。存在しないアカウントの行は空白になります。この関数は GET /info-batch(新しいタブで開きます) を呼び出し、1リクエストで最大100件のプロフィールを、1,000件あたり$0.014からで取得します。
カスタム関数にはGoogleのルールが適用されます。詳細はGoogleのカスタム関数のガイド(新しいタブで開きます)にあります。
- 30秒以内に終了する必要があります。リクエスト1回なら余裕を持って収まります。
- 範囲内のハンドルが変わったときにだけ、再実行されます。カウントを更新するには、範囲内のセルを編集するか、数式を入力し直します。
- キーはスプレッドシートの所有者のユーザープロパティから読み込まれるため、キーを共有しなくても、シートを編集できる全員が使えます。
NOW()やRAND()は絶対に渡さないでください。揮発性の引数を持つカスタム関数は、Googleによって「読み込んでいます...」のまま固まります。
フォロワー数の日付つき履歴が必要な場合は、数式はライブビュー用にとっておき、その行を毎日のトリガーでログ用のタブにコピーしてください。
#コストと、1つのシートに入る量
Sorsa APIの課金は行ごとではなくリクエストごとなので、シートの料金は1リクエストが返す行数で決まります。どの種類の行でも、料金は公式X APIのごく一部です。表は、スクリプトが書き込むデータの種類ごとに、1,000行あたりの料金を示します。
| シート上のデータ | Sorsa API、1,000行あたり | 1リクエストの行数 | 公式X API、1,000行あたり |
|---|---|---|---|
| 検索またはタイムラインのツイート | $0.07から | 20 | $5.00 |
| アカウントのフォロワー | $0.007から | 200 | $10.00 |
| ハンドルのリストから取得するプロフィール | $0.014から | 100 | $10.00 |
検索またはタイムラインのツイート
- Sorsa API、1,000行あたり
- $0.07から
- 1リクエストの行数
- 20
- 公式X API、1,000行あたり
- $5.00
アカウントのフォロワー
- Sorsa API、1,000行あたり
- $0.007から
- 1リクエストの行数
- 200
- 公式X API、1,000行あたり
- $10.00
ハンドルのリストから取得するプロフィール
- Sorsa API、1,000行あたり
- $0.014から
- 1リクエストの行数
- 100
- 公式X API、1,000行あたり
- $10.00
Google側にも上限があります。Googleドライブのファイル制限(新しいタブで開きます)によると、スプレッドシートには最大2,000万セルを保存できるため、スクリプトの10列なら、1つのスプレッドシートは200万行弱になります。データの種類と行数を選ぶと、2つの請求額と、シートがどれだけ埋まるかが分かります。
公式X API
$500
1ポストあたり$0.005
Sorsa API
最安 $7
1,000ツイートあたり最安$0.07、1リクエストにつき20件
10列で100Kツイートを入れると、1シートの20Mセルのうち1Mを使います(5%)。無料の100リクエストでカバーできる件数: 2,000.
同じ行数に対する両方の請求額と、10列の場合にスプレッドシート1つのうち占める割合です。
失敗したリクエストには課金されません。プランの違いは、毎月含まれるリクエスト数だけです。
#代わりにコネクタ系アドオン、n8n、Make、Zapierを使う
Sorsa APIは、カスタムヘッダーつきのHTTPSリクエストを送れるツールなら何でも動くため、ノーコードの方法ではスクリプトが要りません。Googleスプレッドシート用のSorsa APIアドオンはありませんが、Google Workspace Marketplaceにある汎用のコネクタ系アドオンに、次の3つを渡せば同じことができます。
- URL。例:
https://api.sorsa.io/v3/followers?username=acme_coffee_roasters - 名前が
ApiKeyで、値がキーのヘッダー。キーをURLに入れてはいけません。 - 書き込むデータとして
usersまたはtweetsの配列。アドオンが結果のページ送りに対応しているなら、ページネーショントークンとしてnext_cursor。
自動化ツールも同じリクエストを使います。n8nでTwitter APIを使うのガイドでは、Schedule Trigger、Header Auth認証情報を設定したHTTP Requestノード、Split Outノード、行を追記するGoogle Sheetsノードでワークフローを組みます。MakeのHTTPモジュールとZapierのCustom Requestアクションも同じリクエストを送ります。設定方法は、MakeでTwitter APIを使うとZapierのガイドにあります。
ツールを一切使わずに1回だけコピーするなら、無料のエクスポートツールからCSVをダウンロードし、Googleスプレッドシートでファイル > インポート > アップロードを選びます。フォロワーリストには、無料のTwitterフォロワーをCSVにエクスポートツールが同じように使えます。
#Apps ScriptとAPIのエラーを解決する
失敗の多くは、Apps Scriptの実行ログかGoogleの失敗通知メールにメッセージとして表示され、それぞれ原因は1つです。
| メッセージ | 原因 | 対処 |
|---|---|---|
401 {"message":"invalid api key"} | キーに誤字か余分なスペースがある | X data > Set API keyをもう一度実行する |
403 {"message":"missing key in request header"} | ヘッダーが送信されなかった | ヘッダー名を ApiKey のまま正確に保つ |
403 でそれ以外のメッセージ | プランのリクエストを使い切った | アップグレードするか、ダッシュボードで追加リクエストを有効にする |
429 three times in a row | 毎秒20リクエストを超えた | スクリプトのコピーを複数同時に実行しない |
| Exceeded maximum execution time | 実行が6分を超えたか、カスタム関数が30秒を超えた | MAX_PAGES を下げる。フォロワーのエクスポートは自動で再開する |
| Service invoked too many times for one day: urlfetch | URL Fetch呼び出しが1日2万回を超えた | トリガーの実行頻度を下げる |
| IDの末尾が0000になる | A列が数値の列だった | A列をプレーンテキストに設定し、行を削除して再実行する |
401 {"message":"invalid api key"}- 原因
- キーに誤字か余分なスペースがある
- 対処
- X data > Set API keyをもう一度実行する
403 {"message":"missing key in request header"}- 原因
- ヘッダーが送信されなかった
- 対処
- ヘッダー名を
ApiKeyのまま正確に保つ
403でそれ以外のメッセージ- 原因
- プランのリクエストを使い切った
- 対処
- アップグレードするか、ダッシュボードで追加リクエストを有効にする
429 three times in a row- 原因
- 毎秒20リクエストを超えた
- 対処
- スクリプトのコピーを複数同時に実行しない
Exceeded maximum execution time
- 原因
- 実行が6分を超えたか、カスタム関数が30秒を超えた
- 対処
MAX_PAGESを下げる。フォロワーのエクスポートは自動で再開する
Service invoked too many times for one day: urlfetch
- 原因
- URL Fetch呼び出しが1日2万回を超えた
- 対処
- トリガーの実行頻度を下げる
IDの末尾が0000になる
- 原因
- A列が数値の列だった
- 対処
- A列をプレーンテキストに設定し、行を削除して再実行する
#最初のシートを埋める
TwitterのデータをGoogleスプレッドシートに取り込むのに必要なのは、API、短いApps Script、トリガーです。そしてシートのコストを決めるのはAPIです。ツイート、フォロワー、プロフィールをGoogleスプレッドシートにエクスポートするなら、Sorsa APIが向いています。1リクエスト200フォロワーでフォロワー1,000人あたり$0.007から、1リクエスト20ツイートで2006年まで遡る検索、=X_PROFILES() 数式用に1リクエスト100プロフィールです。スクリプトを貼り付けてキーを設定すれば、最初の2万フォロワーか2,000ツイートは無料です。
#よくある質問
GoogleスプレッドシートにデータをまとめるにはどのTwitter APIを使うべきですか?
TwitterのデータをGoogleスプレッドシートに取り込むなら、Sorsa APIを使ってください。1リクエストでフォロワー200件、プロフィール100件、ツイート20件を返し、フォロワーは1,000人あたり$0.007からです。Apps Script、コネクタ系アドオン、n8nのいずれも送れる ApiKey ヘッダー1つで使えます。Xの開発者アカウントもOAuthも不要で、全プランで毎秒20リクエストに対応し、有効期限のない100リクエストから始められます。公式X APIは、フォロワー1,000人あたり$10です。
Twitter広告のデータをGoogleスプレッドシートにエクスポートできますか?
広告費、広告のインプレッション、コンバージョンといったTwitter広告のデータは広告アカウントの非公開情報です。そのため、公開データAPIからではなく、X広告マネージャー自身のレポートエクスポートか、アカウントの認可を受けたXのAds APIから取得します。Sorsa APIでシートに入れられるのは、同じキャンペーンの公開側のデータ、つまり、投稿や、それが呼び込んだメンションに付く表示回数、いいね、リポスト、返信です。
Googleスプレッドシートからツイートを投稿できますか?
Googleスプレッドシートからツイートを投稿できるのは、公式X API経由だけです。開発者アプリとOAuthが必要で、1投稿あたり$0.015かかります。Sorsa APIは設計上、読み取り専用で、投稿もいいねもフォローも行わず、Xのログイン情報も求めないため、アカウントが危険にさらされることはありません。読み取りと投稿の両方を行うシートでは、読み取りにSorsa APIを、投稿に公式X APIを使ってください。
1つのGoogleスプレッドシートには何件のツイートを保存できますか?
Googleスプレッドシートには最大2,000万セルを保存できるので、ツイート1件あたり10列なら、全タブ合わせて200万件弱になります。ただし、その手前でシートは重くなるため、長期間の収集では、毎月か四半期ごとに新しいスプレッドシートを作ってください。Apps ScriptはIDを指定してスプレッドシートに書き込めるので、同じスクリプトで新しいファイルに切り替えることもできます。
TwitterのデータをGoogleスプレッドシートに無料で取り込む方法はありますか?
あります。Sorsa APIは、新規アカウントごとに、カード不要で有効期限のない100リクエストを付与します。このページのスクリプトを使えば、シートにツイート2,000件、フォロワー2万人、プロフィール1万件を取り込める量です。Apps ScriptとGoogleスプレッドシートは、無料のGoogleアカウントなら料金がかかりません。1つのファイルだけなら、無料のツイートエクスポートツールでCSVをダウンロードして、スプレッドシートにインポートできます。
#検証方法
2026年11月2日に、Sorsa APIの最新のAPIリファレンスに沿ってスクリプトを作成し、SpreadsheetApp、UrlFetchApp、PropertiesServiceの代役を用意してNode.jsで実行しました。代役には、リファレンスと同じ形式のレスポンスを渡しています。実行したのは、検索2回、カーソルから再開した3回のフォロワーエクスポート、X_PROFILES 関数、401、403、429の各経路です。掲載しているレスポンスはデモ用の値です。Googleの割り当て、スプレッドシートの制限、カスタム関数のルールはGoogleのページで、Xの料金はdocs.x.comで、いずれも同じ日に確認しました。