お久しぶりです。
n8n の X v2 API ノードを使って画像付きポストを投稿する方法を解説します。
前提
- n8n のセットアップが完了していること
- X アカウントがあり、API キーとシークレットを取得していること
- Developer の設定は 過去記事 を参照してください。
n8n のバージョン
Version 1.104.1
セルフホスト版を使っています。
n8n 上で OAuth2 認証する
一番大事な工程です。
n8nで画像付き投稿をする上で、この工程が9割を占めると言っても過言ではありません。
New Credentials をクリックして、X OAuth2 API を選択します。

Client ID と Client Secret を入力します。
そして、 Connect my account をクリックします。

ここが重要なのですが、別ウィンドウでXの認証画面が表示されます。
※ この別ウィンドウは閉じないでください
URLをコピーするなどして取得します。

メモ帳などに、取得したURLを貼り付けます。
貼り付けたURLの末尾に +media.write を追加します。
つまり、以下のような形です。
修正前: https://twitter.com/i/flow/login?redirect_after_login=${略}read%2Blist.read%2Blist.write
修正後: https://twitter.com/i/flow/login?redirect_after_login=${略}read%2Blist.read%2Blist.write+media.write
修正したURLをブラウザで開きます。
OAuth2 の認証画面が表示されるので認証します。
認証されれば、晴れてn8n 上で X v2 API を使う準備が整いました。

作成する
ここまでできれば、あとはワークフローを作るだけです。
複数の画像をアップロードする場合、n8n がサポートしている X ワークフローは使えないため、HTTP Request ノードを使います。
※ 1枚の画像をアップロードする場合は、X ワークフローを使うことができます。使い方は参考記事を参照してください。
サンプルを次に示します。
このサンプルは、フォームから画像をアップロードし、X v2 APIを使って画像付きポストを投稿するワークフローです。

{
"name": "My workflow 4",
"nodes": [
{
"parameters": {
"formTitle": "test",
"formFields": {
"values": [
{
"fieldLabel": "images",
"fieldType": "file"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.formTrigger",
"typeVersion": 2.2,
"position": [
0,
0
],
"id": "f5add65d-37a3-4c6a-b4e5-58b2899c3215",
"name": "On form submission",
"webhookId": "38a6e9d9-9741-4d9e-97f4-03975625bfd8"
},
{
"parameters": {
"options": {}
},
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [
528,
0
],
"id": "83547b73-6513-4f90-8ede-b476f753da55",
"name": "Loop Over Items"
},
{
"parameters": {
"jsCode": "const mediaIds = $input.all().map((media)=>{\n return media.json.data.id\n});\n\nconst text = \"HogeHoge\";\n\nreturn {\n mediaIds,\n text\n}"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
784,
-32
],
"id": "51699128-1847-4aec-a668-f5663553fe1a",
"name": "Pretreatment"
},
{
"parameters": {
"method": "POST",
"url": "https://api.x.com/2/media/upload",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "twitterOAuth2Api",
"sendBody": true,
"contentType": "multipart-form-data",
"bodyParameters": {
"parameters": [
{
"name": "media_type",
"value": "={{ $json.mimetype }}"
},
{
"name": "media_category",
"value": "tweet_image"
},
{
"parameterType": "formBinaryData",
"name": "media",
"inputDataFieldName": "data"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
800,
112
],
"id": "8eda4f3c-a0c1-40af-a92c-e767ba170121",
"name": "Upload Media to X",
"credentials": {
"twitterOAuth2Api": {
"id": "mB3TR3y1LzKghmao",
"name": "X account(Staging)"
}
}
},
{
"parameters": {
"method": "POST",
"url": "https://api.x.com/2/tweets",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "twitterOAuth2Api",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"text\": {{ $json.text.toJsonString() }},\n \"media\": {\n \"media_ids\": {{ $json.mediaIds.toJsonString() }}\n }\n} ",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1008,
-32
],
"id": "e4bb9b72-17df-4f58-a6c1-cf9d9439777f",
"name": "Publish Post",
"credentials": {
"twitterOAuth2Api": {
"id": "mB3TR3y1LzKghmao",
"name": "X account(Staging)"
}
}
},
{
"parameters": {
"jsCode": "const images = $input.first().json;\nconst binaryData = $input.first().binary;\n\nreturn Object.keys(binaryData).map((binaryKey, index)=>{\n const image = images.images[index];\n \n return {\n json: {\n filename: image.filename,\n mimetype: image.mimetype\n },\n binary: {data: binaryData[binaryKey]}\n };\n});\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
208,
0
],
"id": "72c5083b-9a36-4d27-928f-4eae894abf79",
"name": "Setup Loop"
}
],
"pinData": {},
"connections": {
"On form submission": {
"main": [
[
{
"node": "Setup Loop",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[
{
"node": "Pretreatment",
"type": "main",
"index": 0
}
],
[
{
"node": "Upload Media to X",
"type": "main",
"index": 0
}
]
]
},
"Pretreatment": {
"main": [
[
{
"node": "Publish Post",
"type": "main",
"index": 0
}
]
]
},
"Upload Media to X": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Setup Loop": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "9478d289-170f-4b87-8a4b-8082d4bdf57e",
"meta": {
"instanceId": "f1ea10e2477ea0ca0966ce19137d7a6d60d042c865a530a9bc6a8f603af2cc15"
},
"id": "aaNQmw3dwR0aPnn2",
"tags": []
}
実行
実行するとフォーム画面が表示されるので、任意の画像をアップロードします。

しばらくすると X に画像付きポストが投稿されます。
HogeHoge pic.twitter.com/EPLm6ARNcW
— momijinn.aka+tester (@kana_tester) July 29, 2025
まとめ
n8n を使って X v2 API を利用し、画像付きポストを投稿する方法を紹介しました。
この方法を使えば、画像のアップロードとポストの作成を自動化でき、X上でコンテンツを投稿できるようになります。
この情報は日本語ではあまり見かけないため、少しでも参考になれば幸いです。