{
  "name": "Schedule BlueSky posts and threads using Google Sheets as content calendar",
  "nodes": [
    {
      "id": "247a7105-ed40-4051-bf26-b65d1c23a6ca",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -576,
        0
      ]
    },
    {
      "id": "ce6a92cb-b874-4589-8955-3d3e93be959b",
      "name": "Get row(s) in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        272,
        0
      ]
    },
    {
      "id": "930d47a1-75a7-4b19-babc-3af2f571f437",
      "name": "Sort",
      "type": "n8n-nodes-base.sort",
      "position": [
        880,
        0
      ]
    },
    {
      "id": "16b10c78-8e3f-4764-abbd-5a76ad1d930c",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1168,
        0
      ]
    },
    {
      "id": "f049c216-68dd-45a8-99c6-cd507affee50",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        1472,
        16
      ]
    },
    {
      "id": "cd9bb8fd-18f0-4d26-b3a5-80552c3eeb27",
      "name": "HTTP Download Image",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1648,
        -128
      ]
    },
    {
      "id": "d1bcfb1c-3d1c-4f75-8012-ea7dfea41639",
      "name": "Update row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3440,
        16
      ]
    },
    {
      "id": "abe0d905-1908-46b6-915b-c6685a817b3b",
      "name": "Construct Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        2576,
        16
      ]
    },
    {
      "id": "aba87f26-ec9d-4c60-9c58-cfc2c3d85571",
      "name": "BlueSky Auth",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -96,
        0
      ]
    },
    {
      "id": "35cf5776-c5e9-4b28-a63f-6902dec747c8",
      "name": "Create Post",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2896,
        16
      ]
    },
    {
      "id": "57359aaa-c587-41bd-bb87-d621bcaa3ac8",
      "name": "Update Thread State",
      "type": "n8n-nodes-base.code",
      "position": [
        3184,
        16
      ]
    },
    {
      "id": "0b3ab7f8-88ce-4b85-9f5b-1dbab47af201",
      "name": "Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        -336,
        0
      ]
    },
    {
      "id": "9a06d0c9-6f8a-4e2f-a304-606aa0f4b13a",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1520,
        -288
      ],
      "parameters": {
        "width": 832,
        "height": 624,
        "content": "# 📘 Post Scheduler - How To Use\n**Goal:** Auto-post threads and images from Google Sheets to BlueSky.\n\n**Step 1: Setup Credentials**\nOpen the \"Configuration\" node (first green node) and enter your Blu"
      }
    },
    {
      "id": "a233dfba-973d-49e5-8662-e05e3f8e1de4",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -432,
        -208
      ],
      "parameters": {
        "width": 288,
        "height": 192,
        "content": "### 1- START HERE \nEnter your BlueSky Handle (e.g., steve.bsky.social), App Password and timezone (eg: America/Los_Angeles or Europe/Berlin etc) here.\n\n[Find your timezone name here](https://en.wikipe"
      }
    },
    {
      "id": "aac4a7c0-1898-4c47-9b2f-bf93cd97c866",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        176,
        160
      ],
      "parameters": {
        "width": 304,
        "height": 272,
        "content": "### 3- Google sheets rows \nFetcher Grabs all rows where Status column is \"Ready\". If you want to test, manually add a row with \"Ready\" in your sheet first.\n**Must have columns -**\nContent | Thread ID "
      }
    },
    {
      "id": "28dba190-c8ee-4c2b-a9b7-74cf4bc4545d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -160,
        160
      ],
      "parameters": {
        "width": null,
        "height": 176,
        "content": "### 2- Get access token\nLogin to BlueSky using handle and app password to get the access token. This will be used in all future BlueSky api calls."
      }
    },
    {
      "id": "f3297a25-02b8-497a-a9cb-7d701db9747c",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        800,
        -192
      ],
      "parameters": {
        "width": null,
        "height": 176,
        "content": "### 4- The Thread Organizer\n**Critically important!** This ensures \"Post 1\" runs before \"Post 2\" so threads are built in the correct order."
      }
    },
    {
      "id": "bd26db50-83ca-49f9-93f2-26b581d845dd",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1104,
        -176
      ],
      "parameters": {
        "width": null,
        "height": null,
        "content": "### 5- The Batch Processor\nProcesses posts one by one to ensure we handle image uploads and thread linking correctly."
      }
    },
    {
      "id": "8819caed-b005-4cbc-9196-42d618ee0077",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1520,
        -320
      ],
      "parameters": {
        "width": null,
        "height": null,
        "content": "### 6i- Download Image \nIf an image URL is found, we download it to re-upload it to BlueSky."
      }
    },
    {
      "id": "b010ea61-1685-4b54-bfd6-b544f9461204",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1792,
        -320
      ],
      "parameters": {
        "width": null,
        "height": null,
        "content": "### 6ii- Upload Image \nUpload it to BlueSky's servers to get a \"Blob Link\" before posting."
      }
    },
    {
      "id": "633901dd-5069-4683-90b4-0b990748f569",
      "name": "Upload Blob",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1856,
        -128
      ]
    },
    {
      "id": "182c0acf-5f32-4870-924d-b7b29d6645ec",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2448,
        -240
      ],
      "parameters": {
        "width": 288,
        "height": 208,
        "content": "### 8- Construct Payload\n**The Logic Brain** This script builds the final data packet. It handles:\n\n- Attaching images (if any).\n- Linking replies (if Sequence > 1, it finds the parent ID).\n- Resettin"
      }
    },
    {
      "id": "2a721a10-a65d-44ee-b9a0-7d9610fa8b92",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2816,
        -160
      ],
      "parameters": {
        "width": null,
        "height": null,
        "content": "### 9- Create Post\nCall BlueSky api to create a new post or reply to a post (if its a sequence in a thread)"
      }
    },
    {
      "id": "34a9917c-7dd3-40ea-b977-bfe280a70293",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3072,
        -160
      ],
      "parameters": {
        "width": null,
        "height": null,
        "content": "### 10- Update Thread State\n**Memory Keeper** After a successful post, this saves the Post ID (uri and cid) into memory. The next item in the loop will look here to know which post to reply to."
      }
    },
    {
      "id": "358c9ff0-8ecd-423e-95ed-5e9586b20a07",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3344,
        -160
      ],
      "parameters": {
        "width": null,
        "height": null,
        "content": "### 11- Update Google Sheets \n**The Closer** Writes \"Posted\" back to your sheet and saves the direct link to the live post so you have a record."
      }
    },
    {
      "id": "52b4b478-cb17-421d-a9d0-54ac5ce925cd",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2784,
        -352
      ],
      "parameters": {
        "width": 816,
        "height": 816,
        "content": "# Create post and update Google sheet"
      }
    },
    {
      "id": "8cb827c7-a323-4bf4-8e14-7eefc48718ec",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        112,
        -352
      ],
      "parameters": {
        "width": 592,
        "height": 816,
        "content": "# Inputs"
      }
    },
    {
      "id": "5540c559-3aea-41d6-a799-f44a652da048",
      "name": "Sticky Note14",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        736,
        -352
      ],
      "parameters": {
        "width": 2016,
        "height": 816,
        "content": "# Posting Logic"
      }
    },
    {
      "id": "73100de1-eeb8-48e0-a353-3d9c7b63e725",
      "name": "Attach Image Blob",
      "type": "n8n-nodes-base.merge",
      "position": [
        2160,
        -112
      ]
    },
    {
      "id": "ed94e650-f36e-4f24-8aea-2b42931a572c",
      "name": "Consolidate Streams",
      "type": "n8n-nodes-base.merge",
      "position": [
        2352,
        16
      ]
    },
    {
      "id": "8f1c1597-e6b3-4a97-90df-2a61580fe22f",
      "name": "Sticky Note15",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2064,
        -336
      ],
      "parameters": {
        "width": 272,
        "height": 208,
        "content": "### 6iii- Re-assembling the Data \nThis node merges the \"Blob\" (the technical image file from BlueSky) back with your original Google Sheet data (Text, Thread ID, etc.).\n\nWithout this, the next step wo"
      }
    },
    {
      "id": "f6a33102-6593-4d0e-b6e3-49aa645b1b9f",
      "name": "Sticky Note16",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2272,
        160
      ],
      "parameters": {
        "width": 288,
        "height": 208,
        "content": "### 7- The Reunion\nThis brings your \"Image Posts\" (top path) and \"Text-Only Posts\" (bottom path) back together into a single list.\n\nThis allows the **\"Construct Payload\"** node to handle all posts in "
      }
    },
    {
      "id": "7b50984a-0e71-4f4c-bbc5-28f31bdeaa00",
      "name": "Sticky Note17",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1408,
        144
      ],
      "parameters": {
        "width": null,
        "height": null,
        "content": "### 6- If post contains image\n\nIf we got image url, then download it, upload to BlueSky and then return the combined data.\nElse continue."
      }
    },
    {
      "id": "82b6857a-3698-4477-97ea-cd604f25a5ab",
      "name": "Filter",
      "type": "n8n-nodes-base.filter",
      "position": [
        496,
        0
      ]
    },
    {
      "id": "ad3ac0d7-f1d0-463b-a1ea-e3525589fbcb",
      "name": "Sticky Note18",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        400,
        -208
      ],
      "parameters": {
        "width": 272,
        "height": 192,
        "content": "### 4- Checks Schedule Time \n**Format:** \nYYYY-MM-DD HH:mm\neg: 2025-12-25 14:30\n\n**Important:** Set this column to **\"Plain Text\"** in Google Sheets to prevent errors.\n"
      }
    }
  ],
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "HTTP Download Image",
            "type": "main",
            "index": 0
          },
          {
            "node": "Attach Image Blob",
            "type": "main",
            "index": 1
          }
        ],
        [
          {
            "node": "Consolidate Streams",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Sort": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter": {
      "main": [
        [
          {
            "node": "Sort",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Post": {
      "main": [
        [
          {
            "node": "Update Thread State",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Blob": {
      "main": [
        [
          {
            "node": "Attach Image Blob",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "BlueSky Auth": {
      "main": [
        [
          {
            "node": "Get row(s) in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Configuration": {
      "main": [
        [
          {
            "node": "BlueSky Auth",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [],
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Attach Image Blob": {
      "main": [
        [
          {
            "node": "Consolidate Streams",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Construct Payload": {
      "main": [
        [
          {
            "node": "Create Post",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Consolidate Streams": {
      "main": [
        [
          {
            "node": "Construct Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet": {
      "main": [
        [
          {
            "node": "Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Download Image": {
      "main": [
        [
          {
            "node": "Upload Blob",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Thread State": {
      "main": [
        [
          {
            "node": "Update row in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update row in sheet": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}