本文へスキップ

Twitter 動画 API:X の動画の MP4 URL を取得する

Twitter 動画の MP4 URL は、投稿のメディアデータに入っています。X はアップロードされた動画を最大5種類の MP4 にエンコードし、270pから1080p以上まで、各ファイルの URL をビットレートとともに掲載します。

結論: ビットレートが最も高い MP4 を選びます。GIF は音声のない1本の MP4 です。公式 X API が画質別のファイルを一覧に出すのは media.fields=variants を指定したときだけで、2026年11月22日からは動画投稿1,000件あたり$10.00です。Sorsa API は POST /tweet-info-bulk で各投稿の動画リンクを返します。1リクエストで100投稿、1,000件あたり$0.014からで、100回分の無料リクエストで最初の10,000件を取得できます。

エンドポイント
POST /tweet-info-bulk
1ページの件数
1リクエストあたり100投稿
料金
1,000件あたり$0.014から

#X が動画を保存する仕組み:画質別ファイルとビットレート

X は、投稿者がアップロードしたファイルをそのまま配信することはありません。すべての動画を、サイズ別の MP4 ファイル群と、HLS プレイリスト(再生中にプレーヤーがサイズを切り替えるための .m3u8 形式の索引)に再エンコードします。各 MP4 は音声を含む完全なファイルなので、どれか1つだけをダウンロードして単独で再生できます。1件の投稿なら、無料の Twitter 動画ダウンローダーに貼り付けたリンクからファイルを保存できます。このガイドは、コードでファイルを取得する方法を扱います。

2026年11月2日に、2017年から2026年までの23件の公開投稿の画質別ファイル一覧を読み、X が配信した72個の MP4 ファイルを計測しました。X が各ファイルに記載するビットレートは上限値で、実際のファイルは3倍から5倍小さくなります。

画質フレームサイズ(ピクセル)X が記載するビットレート実測の平均ビットレート
270p480 × 270256 kbps約91 kbps
360p640 × 360832 kbps約233 kbps
720p1280 × 7202,176 kbps約626 kbps
1080p1920 × 108010.4 Mbps約2,172 kbps
  • 270p

    フレームサイズ(ピクセル)
    480 × 270
    X が記載するビットレート
    256 kbps
    実測の平均ビットレート
    約91 kbps
  • 360p

    フレームサイズ(ピクセル)
    640 × 360
    X が記載するビットレート
    832 kbps
    実測の平均ビットレート
    約233 kbps
  • 720p

    フレームサイズ(ピクセル)
    1280 × 720
    X が記載するビットレート
    2,176 kbps
    実測の平均ビットレート
    約626 kbps
  • 1080p

    フレームサイズ(ピクセル)
    1920 × 1080
    X が記載するビットレート
    10.4 Mbps
    実測の平均ビットレート
    約2,172 kbps
The four MP4 files X served for one 82-second 1080p video, real size against listed bitrate 82秒の動画1本: Xが配信した4つのMP4ファイル 実ファイル 予測 270p 表示256 kbps 1.1 MB 2.6 MB 360p 表示832 kbps 2.9 MB 8.5 MB 720p 表示2,176 kbps 7.3 MB 22.2 MB 1080p 表示10.4 Mbps 22.2 MB 105.7 MB 実線バー: Xが配信したファイル。破線の枠は予測: 表示ビットレート × 82秒。 video.twimg.comで2026年11月2日に計測。
82秒の動画の1080pファイルは22.2 MB で、記載されたビットレートから予測される大きさの約5分の1でした。

計測からわかったことは次のとおりです。

  • ビットレートが最も高いものが最良のファイル。 MP4 のエントリをビットレート順に並べ、一番上を選びます。種類が application/x-mpegURL のプレイリストのエントリにはビットレートがなく、ファイルではなく索引です。
  • サイズはフレームの形で変わる。 縦長の動画は320 × 568から1080 × 1920まで、正方形は320 × 320から1080 × 1080までで、1936 × 1548のアップロードには25.1 Mbps の5つ目のファイルが付きました。
  • 1080pでアップロードしても1080pのファイルが付くとは限らない。 2025年と2026年の1920 × 1080のアップロード7件のうち、2件は720pで止まり、2022年より前の投稿の大半は720pが上限です。
  • プレイリストは音声と映像を分けている。 映像のストリームには音声がなく、音声は32、64、128 kbps の別トラックで提供され、動画によっては字幕も付きます。

GIF はもっと単純です。X は GIF 自身のサイズで、音声のないループ再生の MP4 を1つだけ保持し、ほかの画質もプレイリストもありません。

#Sorsa API で動画の MP4 URL を取得する

Twitter(X)API 兼スクレイピングツールである Sorsa API は、各投稿にメディアを付けて返します。動画、GIF、写真はそれぞれ、投稿の entities リストのエントリになっており、type、直接の link、preview 画像を持ちます。公式 X API が求める開発者アカウントと OAuth の代わりに、ヘッダーに API キー1つで済みます。

  1. キーを取得する。 サインアップして、ダッシュボードから API キーをコピーします。最初の100リクエストは無料で、カードは不要です。

  2. 投稿のリンクを送る。 POST /tweet-info(新しいタブで開きます) は、tweet_link に投稿の URL または ID だけを受け付けます。

    ターミナル
    curl -X POST "https://api.sorsa.io/v3/tweet-info" \
      -H "ApiKey: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"tweet_link":
           "https://x.com/northfield_video_lab/status/1984519203377641472"}'
    
    レスポンス200 OK
    {
      "id": "1984519203377641472",
      "created_at": "2026-10-31T16:04:11Z",
      "full_text": "First ride on the new gravel loop.",
      "entities": [
        {
          "type": "video",
          "link": "https://video.twimg.com/amplify_video/1984519110025023488/vid/avc1/480x270/Qm3vTb8xLwK2pRfA.mp4?tag=21",
          "preview": "https://pbs.twimg.com/amplify_video_thumb/1984519110025023488/img/Hx2LkP9aQwErT0bn.jpg"
        }
      ],
      "user": {
        "username": "northfield_video_lab",
        "display_name": "Northfield Video Lab",
        "media_count": 214
      }
    }
    
  3. 動画のエントリを読む。 type が video で、link が video.twimg.com にあるエンティティを残します。リンクに /tweet_video/ というパスがあれば、GIF です。

  4. ファイルをダウンロードする。 MP4 は X のサーバー上にある普通の HTTPS ファイルです。キーも Cookie も不要で、リクエストとして数えられることもありません。

    import requests
    
    API = "https://api.sorsa.io/v3/tweet-info"
    HEADERS = {"ApiKey": "YOUR_API_KEY"}
    
    
    def video_links(post):
        r = requests.post(API, headers=HEADERS,
                          json={"tweet_link": post}, timeout=60)
        r.raise_for_status()  # 403: no key, or no requests left
        tweet = r.json()
        for e in tweet.get("entities") or []:
            if e.get("type") == "video" and "video.twimg.com" in e["link"]:
                yield tweet["id"], e["link"]
    
    
    links = video_links("1984519203377641472")
    for n, (post_id, link) in enumerate(links, 1):
        with open(f"{post_id}_{n}.mp4", "wb") as f:
            f.write(requests.get(link, timeout=120).content)
    

link は音声付きの MP4 で、どこでも再生できます。2026年11月2日に、Sorsa API で動いている当社の無料ダウンローダーで2本の動画を試したところ、どちらのリンクも X の270pのファイルでした。82秒の動画で1.1 MB なので、プレビュー、文字起こし、フレームのサンプリング、大規模なアーカイブには十分軽量です。GIF のリンクは唯一のファイルなので、そのまま完全な形で届きます。

preview は、フルサイズのフレームとしても使えます。.jpg を外したうえで ?format=jpg&name=orig を付けると、X がアップロードされたままのサイズでフレームを返します。テスト用の投稿の1つでは、1936 × 1548ピクセルでした。写真は同じリストに type が photo として入っています。1件の投稿でもアカウント全体でも、元のサイズで取得する方法は、Twitter 画像スクレイパーのガイドで解説しています。

投稿のリストなら、最大100件のリンクまたは ID を tweet_links に入れて POST /tweet-info-bulk(新しいタブで開きます) に送ります。レスポンスは {"tweets": [...]} で、どの投稿にも同じ entities が入っており、バッチ全体が1リクエストです。料金は1,000投稿あたり$0.014からです。

#アカウントや検索結果のすべての動画をダウンロードする

動画付きの投稿は検索で見つけられます。X の検索演算子 filter:native_video は、X にアップロードされた動画付きの投稿に絞り、card_name:animated_gif は GIF に絞ります。POST /search-tweets(新しいタブで開きます) は、条件に一致する投稿を1リクエストあたり約20件返し、2006年まで遡って検索できます。

用途クエリ
1アカウントのすべての動画from:northfield_video_lab filter:native_video
1アカウントのすべての GIFfrom:northfield_video_lab card_name:animated_gif
あるテーマの1か月分の動画"gravel racing" filter:native_video since:2026-10-01 until:2026-11-01
人気の動画だけ#bikepacking filter:native_video min_faves:1000
動画と YouTube のリンクtrail build filter:videos
  • 1アカウントのすべての動画

    クエリ
    from:northfield_video_lab filter:native_video
  • 1アカウントのすべての GIF

    クエリ
    from:northfield_video_lab card_name:animated_gif
  • あるテーマの1か月分の動画

    クエリ
    "gravel racing" filter:native_video since:2026-10-01 until:2026-11-01
  • 人気の動画だけ

    クエリ
    #bikepacking filter:native_video min_faves:1000
  • 動画と YouTube のリンク

    クエリ
    trail build filter:videos

すべての演算子を例付きで解説しているのが、Twitter 検索演算子のガイドです。次のスクリプトは、1つのクエリを最初のページから最後のページまで実行します。

Downloading every video of an X account with Sorsa API 投稿を検索 /search-tweets filter:native_video 1ページ約20件 entitiesを読む type: "video" リンク: MP4、音声あり リンクに/tweet_video/が あればGIF 各ファイルを保存 <post id>_1.mp4 video.twimg.comから 直接 記録 videos.csv id、日付、種類、 バイト数、ファイル 空で返るまで next_cursor
検索の1ページが1リクエストです。動画ファイルは X のサーバーから直接届き、リクエストとして数えられません。
  1. スクリプトを保存する。 next_cursor(次のページの開始位置を示すトークン)を使って検索結果を順にたどり、カーソルが空になるまで続けます。各投稿の動画と GIF を <post id>_<n>.mp4 に書き出し、各ファイルを videos.csv に記録します。

    x_videos.py
    import csv
    import os
    import subprocess
    import sys
    import time
    
    import requests
    
    API = "https://api.sorsa.io/v3/search-tweets"
    HEADERS = {"ApiKey": "YOUR_API_KEY"}
    
    
    def search(body):
        while True:
            r = requests.post(API, headers=HEADERS, json=body, timeout=60)
            if r.status_code == 429:  # over 20 requests a second: wait
                time.sleep(1)
                continue
            r.raise_for_status()  # 403: no key, or no requests left
            return r.json()
    
    
    def videos(tweet):
        """(kind, link) for every video and GIF in a post."""
        for e in tweet.get("entities") or []:
            link = e.get("link") or ""
            if e.get("type") == "video" and "video.twimg.com" in link:
                yield ("gif" if "/tweet_video/" in link else "video"), link
    
    
    def save(link, path):
        with requests.get(link, stream=True, timeout=120) as r:
            r.raise_for_status()
            with open(path, "wb") as f:
                for chunk in r.iter_content(1 << 16):
                    f.write(chunk)
    
    
    def save_hd(post_url, n, path):
        """The post's highest-bitrate MP4 through yt-dlp; False if yt-dlp fails."""
        cmd = ["yt-dlp", "-f", "best[protocol=https]", "--playlist-items", str(n),
               "-o", path, post_url]
        done = subprocess.run(cmd, capture_output=True).returncode == 0
        return done and os.path.exists(path)
    
    
    def run(query, folder, hd=False):
        os.makedirs(folder, exist_ok=True)
        state = os.path.join(folder, "cursor.txt")
        body = {"query": query, "order": "latest"}
        if os.path.exists(state):  # resume a stopped run
            body["next_cursor"] = open(state).read().strip()
        log_path = os.path.join(folder, "videos.csv")
        with open(log_path, "a", newline="", encoding="utf-8") as f:
            log = csv.writer(f)
            while True:
                page = search(body)
                for t in page.get("tweets", []):
                    for n, (kind, link) in enumerate(videos(t), 1):
                        path = os.path.join(folder, f"{t['id']}_{n}.mp4")
                        if os.path.exists(path):
                            continue
                        url = f"https://x.com/{t['user']['username']}/status/{t['id']}"
                        if not (hd and kind == "video" and save_hd(url, n, path)):
                            save(link, path)
                        log.writerow([t["id"], t["created_at"], kind,
                                      os.path.getsize(path), path])
                cursor = page.get("next_cursor")
                if not cursor:
                    break
                body["next_cursor"] = cursor
                with open(state, "w") as s:
                    s.write(cursor)
        if os.path.exists(state):
            os.remove(state)
    
    
    if __name__ == "__main__":
        run(sys.argv[1], sys.argv[2], hd="--hd" in sys.argv[3:])
    
  2. クエリとフォルダを指定して実行する。 python x_videos.py "from:northfield_video_lab filter:native_video" northfield を実行すると、そのアカウントの動画がフォルダ northfield に保存されます。403 はキーがない、またはリクエスト残量がないこと、429 は1秒に20リクエストを超えたことを示し、スクリプトは1秒待って再試行します。

  3. いつでも再実行できる。 すでにディスクにあるファイルはスキップされ、カーソルはページごとに保存されます。止まった実行は続きから再開し、再実行すれば新しい動画だけが追加されます。

アカウント全体の動画でも、リクエストは少なく済みます。検索が返すのは動画付きの投稿だけなので、1ページ約20投稿なら、動画300本のアカウントは約15リクエストです。テキストやそのほかの投稿フィールドをスプレッドシートに入れたい場合は、ユーザーの全ツイートをダウンロードをご覧ください。

#投稿の720pや1080pのファイルを取得する

投稿の720pや1080pのファイルが必要なら、そのリンクを、オープンソースのコマンドラインダウンローダーである yt-dlp に渡します。yt-dlp は X にログインせずに公開投稿を読み取れます。次のフォーマット指定で、ビットレートが最も高い MP4 が選ばれます。

ターミナル
yt-dlp -f "best[protocol=https]" -o "%(id)s.%(ext)s"   "https://x.com/northfield_video_lab/status/1984519203377641472"

上のスクリプトに --hd を付けると、すべての動画でこの処理を行い、yt-dlp が失敗したときは API のリンクで保存します。82秒のテスト動画では、yt-dlp 2026.10.26 が1920 × 1080のファイルを選びました。-F で表示したフォーマット一覧では、このファイルは約100 MiB とされていました。一覧は記載されたビットレートに長さを掛けて算出するためで、実際にダウンロードしたファイルは22.2 MB でした。yt-dlp は自分の IP アドレスから1投稿ずつ取得するので、まとめて探すのは Sorsa API に任せ、yt-dlp には必要な HD ファイルだけを取得させます。

知っておきたいこと

公式 X API も、指定すれば画質別ファイルの一覧全体を1回のレスポンスで返します。投稿の取得に expansions=attachments.media_keys と media.fields=variants を付けると、各動画が includes.media に、bit_rate、content_type、url を持つ variants 配列付きで返ります。開発者アカウントと OAuth が必要で、2026年11月22日からは、このレスポンスに含まれるメディアオブジェクト1件ごとに、投稿読み取りの$0.005に加えて$0.005が課金されます。

#API で扱う Twitter の GIF

X に投稿された GIF は、MP4 として返ります。X は投稿時に、すべての GIF を短い、音声のない、ループ再生の動画に変換するからです。リンクは video.twimg.com/tweet_video/ 上にあり、X は他のサイズを保持しないので、その1ファイルが存在する最良のコピーです。X 自身のデータでは種類が animated_gif、ビットレートが0です。Sorsa API の entities では、video として届き、リンクに /tweet_video/ というパスが含まれます。

.gif ファイルに戻すには、色をきれいに保つために、パレット生成のパスを付けて ffmpeg を実行します。

ターミナル
ffmpeg -i 1211797914437259264_1.mp4 \
  -vf "fps=15,split[a][b];[a]palettegen[p];[b][p]paletteuse" \
  -loop 0 1211797914437259264.gif

ファイルはかなり大きくなります。テストでは、83 KB の MP4 が、同じ498 × 272ピクセルのまま1.76 MB の GIF になり、21倍の大きさでした。保存とプレーヤーには MP4 を残し、ページやチャットで必要な場面にだけ GIF を作ってください。コードなしで GIF を1つ保存するなら、無料の Twitter GIF ダウンローダーが、投稿のリンクから保存します。

#リクエスト数と保存容量で見る費用

Sorsa API では、投稿の費用は、どんなメディアが付いていても同じです。ID で取得する投稿は1,000件あたり$0.014から(1リクエスト100件)、検索で見つける投稿は1,000件あたり$0.07から(1リクエスト約20件)です。動画ファイルは X のサーバーからダウンロードされ、リクエストとして数えられません。公式 X API では、すべての動画がメディア拡張で届き、2026年11月22日からはX が拡張オブジェクトに(新しいタブで開きます)標準レートで課金します。動画投稿1件は、投稿の$0.005にメディアの$0.005を加えた額で、1,000件あたり$10.00です。

動画リンクの取得方法必要なもの動画投稿1,000件あたりの料金
Sorsa API、ID 指定の投稿API キー1つ$0.014から
Sorsa API、検索API キー1つ$0.07から
公式 X API開発者アカウントと OAuth2026年11月22日から$10.00
  • Sorsa API、ID 指定の投稿

    必要なもの
    API キー1つ
    動画投稿1,000件あたりの料金
    $0.014から
  • Sorsa API、検索

    必要なもの
    API キー1つ
    動画投稿1,000件あたりの料金
    $0.07から
  • 公式 X API

    必要なもの
    開発者アカウントと OAuth
    動画投稿1,000件あたりの料金
    2026年11月22日から$10.00
動画投稿数

公式 X API

$10,000

動画投稿100万件の場合

動画投稿1件 $0.010、11月22日から

Sorsa API

$14から

動画投稿100万件の場合

1,000件あたり$0.014から

コストは714分の1

公式 X API の従量課金の料金(新しいタブで開きます)は、請求サイクルあたり300万件の投稿読み取りでも止まり、それを超えると X が販売するのは Enterprise 契約だけです。Sorsa API は全プランで毎秒20リクエストなので、100投稿のバッチなら毎秒2,000件の動画投稿を取得でき、失敗したリクエストは課金されません。

動画のアーカイブでは、保存容量のほうが大きな費用になり、件数よりも画質で大きく変わります。計測した実際の平均ビットレートでは、30秒の動画1,000本が、270pで約0.3 GB、720pで2.3 GB、1080pで8.1 GB です。長さと本数を入力してみてください。

秒
本
画質動画1本あたり全動画上限値
270p0.34 MB341 MB0.96 MB
360p0.87 MB874 MB3.1 MB
720p2.3 MB2.3 GB8.2 MB
1080p8.1 MB8.1 GB38.9 MB

動画1本あたり: 画質ごとの実測ビットレートの中央値(91、233、626、2,172 kbps)。上限値: Xが公開しているビットレート(256、832、2,176 kbps、10.4 Mbps)に長さを掛けた値です。

動画1本あたりのサイズは、2026年11月2日にXのサーバー上で測定した63個のMP4ファイルの、実測の平均ビットレートに基づきます。上限値には、Xが公開しているビットレートを使っています。

#コードで X の動画を取得し始める

コードで X の動画や GIF の MP4 URL を取得するなら、Sorsa API を使ってください。1リクエストで最大100投稿を、各動画のリンク付きで、1,000件あたり$0.014からで取得できます。検索では、2006年まで遡って、アカウントやテーマのすべての動画が見つかり、自分の X アカウントが関わることはありません。スクリプトをコピーしてキーを入れれば、100回分の無料リクエストで、最初の10,000件の動画投稿のリンクが手に入ります。

#よくある質問

公式 X API は Twitter の動画 URL を返しますか?

はい。投稿の取得または検索に expansions=attachments.media_keys と media.fields=variants を追加すると、includes.media の各動画が、MP4 の画質別ファイルを bit_rate と url 付きで一覧に出すので、ビットレートが最も高いものを選びます。この2つのパラメータがないと、プレビュー画像しか返りません。開発者アカウントと OAuth が必要で、2026年11月22日からは、メディアオブジェクト1件ごとに$0.005が、投稿読み取りの$0.005に加算されます。

Twitter の動画 URL を取得するには、どの API を使えばよいですか?

Sorsa API を使ってください。POST /tweet-info-bulk は、1リクエストで最大100投稿を、各動画の MP4 リンクとプレビュー付きで、1,000投稿あたり$0.014からで返します。公式 X API は、2026年11月22日から動画投稿1,000件あたり$10.00です。Sorsa API に必要なのは、開発者アカウントと OAuth ではなく API キー1つで、検索なら2006年まで遡って動画を見つけられ、全プランで毎秒20リクエストに対応します。

ダウンロードした Twitter の動画がぼやけるのはなぜですか?

おそらく、小さい画質のファイルを保存したためです。X は各動画を最大5つの MP4(270pから1080p以上)として保持しており、ツールや API によっては、最初の、あるいは最も軽いものを渡します。一覧でビットレートが最も高い MP4 を選んでください。最良のファイルでも720pなら、そのアップロードには1080pのファイルが付いていません。2025年と2026年の1080pのアップロード7件のうち、2件が720pで止まっていました。

非公開アカウントや削除された投稿の動画をダウンロードできますか?

できません。非公開アカウントの投稿は、承認したフォロワーにしか見えないため、Sorsa API を含め、どの API でも動画を取得できず、そのリクエストが課金されることもありません。削除された投稿は X の検索や取得から消えるので、どの API もそれを一覧にできません。削除前に保存したコピーだけが、動画を残しています。

X の動画をダウンロードするのは合法ですか?

はい。研究、モデレーション、アーカイブのために公開動画を保存することは合法で、広く行われています。著作権は各動画を作った人に残るため、ファイルを公開したり再販したりする前に、所有者の許可を得てください。Sorsa API は独自の API を通じて公開投稿を読み取るため、自分の X アカウントは関わりません。

#検証方法

2026年11月2日に、2017年から2026年までの23件の公開動画・GIF 投稿について X が公開している画質別ファイルの一覧を読み、video.twimg.com が配信した75個の MP4 ファイルのうち72個を計測しました。1本の動画については、HLS プレイリストも読み、ログアウト状態の yt-dlp 2026.10.26 でフォーマット一覧も確認しました。うち3件の投稿を、Sorsa API で動いている当社の無料ダウンローダーに通し、返されるリンクを確認しました。スクリプトは、実際のリンクを返す API の代役に対して実行し、ffmpeg のコマンドは実際の GIF ファイルで実行しました。エンドポイントとフィールドは公開 Sorsa API リファレンスに、X のメディアフィールドと料金は、同日に読んだ docs.x.com と2026年10月23日付の X のお知らせに基づいています。

Sorsa APIチーム 読み取り専用のX(Twitter)APIとスクレイピングツール、Sorsa APIを開発・運営しています。2022年から本番稼働し(旧TweetScout API)、累計60億リクエスト以上を処理しています。 Sorsa APIについて

変更点
  • 全面的に書き直しました。72個の MP4 ファイルの実測の画質別ファイルとビットレート、1件の投稿・リスト・アカウント全体を対象にした Sorsa API の方法と動作確認済みスクリプト、MP4 としての GIF、保存容量の計算ツール、X の11月22日からのメディア課金を含む費用を追加しました。2026-06-09: 初公開。