{
  "name": "Generate LinkedIn posts with Nano Banana AI images and auto post them from Google Sheets",
  "nodes": [
    {
      "id": "73de490d-4741-463b-a539-7a18938f3af0",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -643,
        -97
      ],
      "parameters": {
        "width": 520,
        "height": 771,
        "content": "## Write LinkedIn posts with an AI image and post them from a list of topics\nTurn topics from Google Sheets into LinkedIn posts with their own image: every weekday Gemini writes the post, Nano Banana draws the image and PostWire publishes both on LinkedIn, Facebook and Bluesky.\n\n### How it works\n1. **Every weekday at 9:00** reads the rows marked ready. **Take the next topic** picks the first and **Mark the topic as writing** claims it.\n2. **Write the posts with Gemini** returns a LinkedIn post, a shorter Facebook and Bluesky version and the brief for the image.\n3. **Nano Banana image** (Gemini) generates the image from that brief.\n4. **Post to LinkedIn, Facebook, Bluesky** (PostWire) uploads the image and publishes each text on its network.\n5. **Mark the topic as posted** writes the post links in the row. When the image or a network fails, **Write the fix in the row** and **Email me the fix** tell you what to fix.\n\n### Setup\n1. Install the verified **PostWire** node (search \"PostWire\" in the nodes panel), create an account at postwire.io, connect your networks and paste your API key into a **PostWire API** credential.\n2. Add a Google Gemini credential to both Gemini nodes. The text fits the free tier; a Nano Banana image costs about 0.04 USD.\n3. Create a sheet with the columns topic, notes, status, posted_at, links and note. Write ready in status to queue a topic, and pick the sheet in the four Sheets nodes.\n4. Connect Gmail and fill in **Post settings**.\n\n### Customize\nChange the voice and image style in Post settings, or the networks in the PostWire node (the free plan posts to 2 networks per post)."
      },
      "typeVersion": 1
    },
    {
      "id": "90129020-c0c2-49a1-abde-ccae208d1c5e",
      "name": "Sticky Note 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -63,
        -97
      ],
      "parameters": {
        "color": 7,
        "width": 1741,
        "height": 271,
        "content": "## 1. Next topic\nThe first row marked ready, claimed before anything is written."
      },
      "typeVersion": 1
    },
    {
      "id": "64f7f1cd-2964-46fe-aee9-c6749024196a",
      "name": "Sticky Note 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1716,
        -97
      ],
      "parameters": {
        "color": 7,
        "width": 525,
        "height": 271,
        "content": "## 2. Write with Gemini\nOne post per network and the brief for the image."
      },
      "typeVersion": 1
    },
    {
      "id": "3f86fb84-28ff-4627-aa85-b9765bcec220",
      "name": "Sticky Note 4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -25,
        431
      ],
      "parameters": {
        "color": 7,
        "width": 538,
        "height": 295,
        "content": "## 3. Image and post\nNano Banana draws the image; PostWire uploads it and publishes each text."
      },
      "typeVersion": 1
    },
    {
      "id": "ece78284-e360-4273-a2fd-af98769fa516",
      "name": "Sticky Note 5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        544,
        335
      ],
      "parameters": {
        "color": 7,
        "width": 1103,
        "height": 511,
        "content": "## 4. Log and alert\nThe post links in the row, or the fix in the row and by email."
      },
      "typeVersion": 1
    },
    {
      "id": "b32979b5-d854-4c4b-af0e-b798a47b25fa",
      "name": "Every weekday at 9:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1,
                2,
                3,
                4,
                5
              ],
              "triggerAtHour": 9
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "7fea7c8e-8190-4761-a289-acd7727b20c8",
      "name": "Post settings",
      "type": "n8n-nodes-base.set",
      "position": [
        300,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1f717425-3f09-4a00-a490-c6c018a88442",
              "name": "voice",
              "type": "string",
              "value": "Plain and specific, first person plural, short sentences, no hype and no emojis"
            },
            {
              "id": "16abb4c9-2a72-4638-a266-aa18a995725e",
              "name": "image_style",
              "type": "string",
              "value": "Flat editorial illustration, landscape 16:9, calm colours, no text, no logos, no real people"
            },
            {
              "id": "7d77f2ff-05bb-425e-a151-3e3564b3eb6e",
              "name": "email",
              "type": "string",
              "value": "you@example.com"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "0b2ecedf-3076-4eb3-a775-763a1f6293ae",
      "name": "Read the topics",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        600,
        0
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "ready",
              "lookupColumn": "status"
            }
          ]
        },
        "operation": "read",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "cac7c40c-de94-47ed-a7c7-2ae7688dfbcb",
      "name": "Has a topic",
      "type": "n8n-nodes-base.filter",
      "position": [
        900,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "3e635935-9c72-4eea-a43e-dd9d48bf7514",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ String($json.topic || '').trim() }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "433dff37-e21f-4f07-a5a8-7dd5765eb34b",
      "name": "Take the next topic",
      "type": "n8n-nodes-base.limit",
      "position": [
        1200,
        0
      ],
      "parameters": {
        "maxItems": 1
      },
      "typeVersion": 1
    },
    {
      "id": "170533f6-7381-4a58-a1cd-911f5acb5b62",
      "name": "Mark the topic as writing",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1500,
        0
      ],
      "parameters": {
        "columns": {
          "value": {
            "status": "writing",
            "row_number": "={{ $json.row_number }}"
          },
          "schema": [
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "e6ffbe0d-6398-4816-a885-f13255490d44",
      "name": "Write the posts with Gemini",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "position": [
        1800,
        0
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "id",
          "value": "models/gemini-2.5-flash"
        },
        "options": {
          "systemMessage": "You write social media posts for a business from one topic. Use only the facts in the notes and invent no numbers. Return JSON with the keys linkedin (a hook line, then 3 or 4 short paragraphs separated by blank lines and a closing question, up to 1300 characters, no hashtags), facebook (1 or 2 conversational sentences), bluesky (up to 280 characters) and image_prompt (one paragraph that describes a single image illustrating the idea in the given image style, with no text in the image)."
        },
        "messages": {
          "values": [
            {
              "content": "={{ 'Topic: ' + $('Take the next topic').item.json.topic + '\\nNotes and facts: ' + ($('Take the next topic').item.json.notes || 'none') + '\\nVoice: ' + $('Post settings').first().json.voice + '\\nImage style: ' + $('Post settings').first().json.image_style }}"
            }
          ]
        },
        "resource": "text",
        "operation": "message",
        "jsonOutput": true
      },
      "typeVersion": 1.2
    },
    {
      "id": "8c3e7a5b-01c7-4ab1-a5bb-eee45039118b",
      "name": "Read the plan",
      "type": "n8n-nodes-base.set",
      "position": [
        2100,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "89dce144-25d2-4b4b-a173-99405ad8e696",
              "name": "plan",
              "type": "object",
              "value": "={{ JSON.parse($('Write the posts with Gemini').item.json.content.parts.map(p => p.text || '').join('')) }}"
            },
            {
              "id": "eea9dd89-aa7d-4762-a95b-bd1df19cd687",
              "name": "topic",
              "type": "string",
              "value": "={{ $('Take the next topic').item.json.topic }}"
            },
            {
              "id": "6e23eacf-7434-42d2-a9c3-80428636eb21",
              "name": "row_number",
              "type": "number",
              "value": "={{ $('Take the next topic').item.json.row_number }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "84150e5f-2b5b-4d6f-af3b-5a2d1b04a887",
      "name": "Nano Banana image",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "onError": "continueRegularOutput",
      "position": [
        0,
        552
      ],
      "parameters": {
        "prompt": "={{ $json.plan.image_prompt || ($json.topic + '. ' + $('Post settings').first().json.image_style) }}",
        "modelId": {
          "__rl": true,
          "mode": "id",
          "value": "models/gemini-2.5-flash-image"
        },
        "options": {},
        "resource": "image",
        "operation": "generate"
      },
      "typeVersion": 1.2
    },
    {
      "id": "0405f4f5-8181-4049-a104-2278f096955a",
      "name": "Post to LinkedIn, Facebook, Bluesky",
      "type": "n8n-nodes-postwire.postWire",
      "onError": "continueRegularOutput",
      "position": [
        300,
        552
      ],
      "parameters": {
        "drafts": "={{ Object.fromEntries(['linkedin', 'facebook', 'bluesky'].map(n => [n, { text: $('Read the plan').item.json.plan[n] || $('Read the plan').item.json.plan.linkedin }])) }}",
        "options": {
          "mediaType": "image",
          "idempotencyKey": "={{ ('image-topic-row-' + $('Read the plan').item.json.row_number + '-' + $('Read the plan').item.json.topic).slice(0, 200) }}"
        },
        "resource": "post",
        "operation": "publish",
        "platforms": [
          "linkedin",
          "facebook",
          "bluesky"
        ],
        "contentMode": "drafts",
        "mediaSource": "binary",
        "binaryPropertyName": "data"
      },
      "typeVersion": 2
    },
    {
      "id": "b410d68f-c735-4d5b-a7b8-75f4e46e998b",
      "name": "Collect the results",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        600,
        552
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "results"
      },
      "typeVersion": 1
    },
    {
      "id": "544dd09a-f552-491e-ac22-1d6882eea022",
      "name": "Everything published?",
      "type": "n8n-nodes-base.if",
      "position": [
        900,
        552
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "4b7ab2c2-8121-4b85-a8c1-b5ce28a14916",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.results.length > 0 && $json.results.every(r => r.ok === true) }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "6bcbfa67-b4ca-4050-aaf4-582bc9151a54",
      "name": "Mark the topic as posted",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1200,
        431.99999999999994
      ],
      "parameters": {
        "columns": {
          "value": {
            "note": "",
            "links": "={{ $json.results.map(r => r.platform + ' ' + (r.url || '')).join(' | ') }}",
            "status": "posted",
            "posted_at": "={{ $now.toFormat('yyyy-MM-dd HH:mm') }}",
            "row_number": "={{ $('Read the plan').first().json.row_number }}"
          },
          "schema": [
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "posted_at",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "posted_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "links",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "links",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "note",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "note",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "b6e7eed6-456e-4414-a81f-a9ed61e706b5",
      "name": "Write the fix in the row",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1200,
        672
      ],
      "parameters": {
        "columns": {
          "value": {
            "note": "={{ (() => { const s = $('Nano Banana image').first().json.error; if (s) return 'Gemini did not generate the image: ' + (s.message || s); return $json.results.filter(r => r.ok !== true).map(r => (r.platform || 'all networks') + ': ' + r.error + (r.hint || r.description ? ' ' + (r.hint || r.description) : '')).join(' | '); })() }}",
            "links": "={{ $json.results.filter(r => r.ok === true).map(r => r.platform + ' ' + (r.url || '')).join(' | ') }}",
            "status": "={{ $json.results.some(r => r.ok === true) ? 'partly posted' : 'needs fix' }}",
            "posted_at": "={{ $now.toFormat('yyyy-MM-dd HH:mm') }}",
            "row_number": "={{ $('Read the plan').first().json.row_number }}"
          },
          "schema": [
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "posted_at",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "posted_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "links",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "links",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "note",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "note",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "90d1da17-1a8b-4932-a68f-d21c31cbc638",
      "name": "Email me the fix",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1500,
        672
      ],
      "parameters": {
        "sendTo": "={{ $('Post settings').first().json.email }}",
        "message": "={{ 'Topic: ' + $('Read the plan').first().json.topic + '\\n\\nWhat happened and how to fix it:\\n' + $json.note + ($json.links ? '\\n\\nPublished: ' + $json.links : '') + '\\n\\nSet the row back to ready to try again.' }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "={{ 'LinkedIn post not published everywhere: ' + String($('Read the plan').first().json.topic).slice(0, 80) }}",
        "emailType": "text"
      },
      "typeVersion": 2.1
    }
  ],
  "connections": {
    "Has a topic": {
      "main": [
        [
          {
            "node": "Take the next topic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post settings": {
      "main": [
        [
          {
            "node": "Read the topics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read the plan": {
      "main": [
        [
          {
            "node": "Nano Banana image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read the topics": {
      "main": [
        [
          {
            "node": "Has a topic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Nano Banana image": {
      "main": [
        [
          {
            "node": "Post to LinkedIn, Facebook, Bluesky",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Collect the results": {
      "main": [
        [
          {
            "node": "Everything published?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Take the next topic": {
      "main": [
        [
          {
            "node": "Mark the topic as writing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every weekday at 9:00": {
      "main": [
        [
          {
            "node": "Post settings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Everything published?": {
      "main": [
        [
          {
            "node": "Mark the topic as posted",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Write the fix in the row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write the fix in the row": {
      "main": [
        [
          {
            "node": "Email me the fix",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark the topic as writing": {
      "main": [
        [
          {
            "node": "Write the posts with Gemini",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write the posts with Gemini": {
      "main": [
        [
          {
            "node": "Read the plan",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post to LinkedIn, Facebook, Bluesky": {
      "main": [
        [
          {
            "node": "Collect the results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "active": false
}
