This workflow corresponds to n8n.io template #12156 — we link there as the canonical source.
This workflow follows the Google Sheets → HTTP Request recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "z3jqwXEftE3owiCT",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "BlueSky Suite: Track BlueSky post analytics in Google Sheets",
"tags": [],
"nodes": [
{
"id": "fb306bc5-06c1-43f9-847e-e137508e8425",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-1232,
-16
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 9
}
]
}
},
"typeVersion": 1.2
},
{
"id": "c36fba80-c89f-42ea-ae06-20ff592a8bfc",
"name": "Get row(s) in sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-432,
-16
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "Posted",
"lookupColumn": "Status"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "86c103ad-5359-4d8b-a977-12dc2252eac2",
"name": "Get Post Stats",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
560,
0
],
"parameters": {
"url": "https://bsky.social/xrpc/app.bsky.feed.getPosts",
"options": {},
"sendQuery": true,
"sendHeaders": true,
"queryParameters": {
"parameters": [
{
"name": "uris",
"value": "=at://{{ $('BlueSky Auth').first().json.did }}/app.bsky.feed.post/{{ $('Loop Over Items').item.json[\"Post Link\"].split(\"/post/\")[1] }}"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $('BlueSky Auth').first().json.accessJwt }}"
}
]
}
},
"typeVersion": 4.3
},
{
"id": "276afa3f-3de1-4a9c-ad98-02e5a58b8d60",
"name": "Update row in sheet",
"type": "n8n-nodes-base.googleSheets",
"onError": "continueRegularOutput",
"position": [
944,
0
],
"parameters": {
"columns": {
"value": {
"Like Count": "={{ $json?.posts[0]?.likeCount || 0 }}",
"row_number": "={{ $('Loop Over Items').item.json.row_number }}",
"Reply Count": "={{ $json?.posts[0]?.replyCount || 0 }}",
"Repost Count": "={{ $json?.posts[0]?.repostCount || 0 }}"
},
"schema": [
{
"id": "Content",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Content",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Thread ID",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Thread ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Sequence",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Sequence",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Image URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Image URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Scheduled Time",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Scheduled Time",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Post Link",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Post Link",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Post URI",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Post URI",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Like Count",
"type": "string",
"display": true,
"required": false,
"displayName": "Like Count",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Repost Count",
"type": "string",
"display": true,
"required": false,
"displayName": "Repost Count",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Reply Count",
"type": "string",
"display": true,
"required": false,
"displayName": "Reply Count",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "number",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"row_number"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "bd75f8c6-b009-43b0-8f46-9714c9309fc2",
"name": "Configuration",
"type": "n8n-nodes-base.set",
"position": [
-1024,
-16
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "4e2b2be1-d052-4dc8-96e8-60054b1cba1d",
"name": "bluesky_handle",
"type": "string",
"value": ""
},
{
"id": "b336da17-f730-49e6-85c9-4f8e9b3f8522",
"name": "app_password",
"type": "string",
"value": ""
},
{
"id": "3f701790-b159-490a-a656-13e170f1a8a1",
"name": "timezone",
"type": "string",
"value": "Asia/Kolkata"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "4f57d122-012f-4185-8f23-812acc87e00d",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2000,
-240
],
"parameters": {
"width": 640,
"height": 496,
"content": "# \ud83d\udcc8 Analytics Bot - How To Use\n**Goal:** Keep your engagement stats (Likes, Reposts, Replies) updated automatically in the same Google Sheet that you use for content scheduling . Make sure your Google Sheet has all the columns required. [**Sample Google Sheet**](https://docs.google.com/spreadsheets/d/1Mg04gK1K5DBtJHrWw3ePRFc_JjkxwAp0deGjapVl2q0/edit?usp=sharing)\n\n**Step 1:** Open the \"Configuration\" node and enter your BlueSky Handle and App Password and your timezone\n\n**Step 2:** The \"Active Window\" Strategy To save API calls, this workflow only checks posts from the last 14 days.\n\n**Day 1-14:** Checks daily to catch viral spikes.\n\n**Day 15+:** Stops checking (Post is considered \"Archived\").\n\n**Step 3:** Activate Turn on the workflow. It runs daily (e.g., 9 AM) and updates the rows in your sheet without creating duplicates."
},
"typeVersion": 1
},
{
"id": "ad79671f-e383-4456-9cd8-d55bc58b29dd",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-160,
-224
],
"parameters": {
"width": 256,
"height": 192,
"content": "### 4- The Gatekeeper\nChecks that 'Posted At' and 'Post Link' are not empty to prevent errors on blank or failed rows.\n\nThen it only allows posts where 'Posted At' date is within the last 14 days.\n"
},
"typeVersion": 1
},
{
"id": "78a1f0b3-2661-413f-8aea-d3cf8103f02d",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1088,
-224
],
"parameters": {
"width": 288,
"height": 176,
"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.wikipedia.org/wiki/List_of_tz_database_time_zones)"
},
"typeVersion": 1
},
{
"id": "a2d78b89-7a98-473a-abc4-c052346f1094",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-864,
144
],
"parameters": {
"width": 256,
"height": 144,
"content": "### 2- Get access token\nAuthenticates with BlueSky to retrieve an Access Token. This token is used for all subsequent API calls."
},
"typeVersion": 1
},
{
"id": "73cc8432-0844-428a-9e60-11cd573ae9f2",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-512,
-176
],
"parameters": {
"height": 144,
"content": "### 3- Google sheets rows \nFetches all rows where Status is 'Posted'. To test, ensure your sheet has at least one row marked as 'Posted'."
},
"typeVersion": 1
},
{
"id": "9474744d-e05d-4ce5-93eb-9decda6b5e53",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
448,
-224
],
"parameters": {
"width": 272,
"height": 192,
"content": "### 6- Resilient Fetcher\nFetches post metrics from BlueSky.\nConfigured to \"Continue on Error\". If a post was deleted from BlueSky, this node returns an error JSON instead of crashing the workflow."
},
"typeVersion": 1
},
{
"id": "69564433-dd8d-49b6-bc1d-f9645be6095c",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
800,
-224
],
"parameters": {
"width": 272,
"height": 192,
"content": "### 7- Safe Updater \nUpdates the Google Sheet.\nUses special \"Safe Logic\" (|| 0). If the post was deleted (returns 404), it writes 0 into the stats columns instead of breaking the automation."
},
"typeVersion": 1
},
{
"id": "f49c2556-07eb-44be-b21a-f3a7fd248912",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
192,
144
],
"parameters": {
"width": 320,
"height": 192,
"content": "### 5- The Batch Processor \nThis node takes the filtered list of \"Active Posts\" (from the last 14 days) and processes them one by one.\n\nIt ensures that if one post fails (e.g., deleted), it doesn't stop the entire workflow, allowing the rest of your stats to update successfully."
},
"typeVersion": 1
},
{
"id": "5706bed9-7b6d-446c-99cf-e336ca958260",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
-544,
-336
],
"parameters": {
"color": 7,
"width": 672,
"height": 704,
"content": "# Input"
},
"typeVersion": 1
},
{
"id": "f945d73e-f59a-44b5-98a1-9bd1094f9957",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
160,
-336
],
"parameters": {
"color": 7,
"width": 944,
"height": 704,
"content": "# Processing"
},
"typeVersion": 1
},
{
"id": "972cd0de-e7e7-41e9-ae39-35f2583d623d",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
240,
-16
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "141f80a2-7974-405a-85f3-d1601af95ad3",
"name": "Filter1",
"type": "n8n-nodes-base.filter",
"position": [
-112,
-16
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "b6ab450f-c868-4582-b4f9-8b7e98974238",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json['Post Link'] }}",
"rightValue": ""
},
{
"id": "83f5b4cd-09c9-4b57-adab-fc6960d4c5f7",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json['Posted At'] }}",
"rightValue": ""
},
{
"id": "5d651b8d-26e0-4f26-abf2-52dd2cb916bf",
"operator": {
"type": "dateTime",
"operation": "after"
},
"leftValue": "={{ DateTime.fromFormat($json['Posted At'], 'yyyy-MM-dd HH:mm', { zone: $('Configuration').first().json.timezone }) }}",
"rightValue": "={{ $now.setZone($('Configuration').first().json.timezone || 'UTC').minus({days: 14}) }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "9d4160cc-fc59-4ccf-aa1d-bd96c9d5ccbd",
"name": "BlueSky Auth",
"type": "n8n-nodes-base.httpRequest",
"position": [
-784,
-16
],
"parameters": {
"url": "https://bsky.social/xrpc/com.atproto.server.createSession",
"method": "POST",
"options": {},
"jsonBody": "={\n \"identifier\":\"{{$('Configuration').first().json.bluesky_handle}}\",\n \"password\": \"{{ $('Configuration').first().json.app_password }}\"\n}",
"sendBody": true,
"specifyBody": "json"
},
"typeVersion": 4.3
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "406642f8-0dc8-4b1f-9367-a5643fca02c8",
"connections": {
"Filter1": {
"main": [
[
{
"node": "Loop Over Items",
"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
}
]
]
},
"Get Post Stats": {
"main": [
[
{
"node": "Update row in sheet",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "Get Post Stats",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Configuration",
"type": "main",
"index": 0
}
]
]
},
"Get row(s) in sheet": {
"main": [
[
{
"node": "Filter1",
"type": "main",
"index": 0
}
]
]
},
"Update row in sheet": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
googleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automatically syncs engagement metrics (Likes, Reposts, Replies) from BlueSky back to your content calendar in Google Sheets. It ensures your reporting is always up to date without manual data entry.
Source: https://n8n.io/workflows/12156/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This workflow automates video distribution to 9 social platforms simultaneously using Blotato's API. It includes both a scheduled publisher (checks Google Sheets for videos marked "Ready") and a subwo
YogiAI. Uses googleSheets, googleSheetsTool, httpRequest, stopAndError. Scheduled trigger; 61 nodes.
This workflow monitors Google Calendar for events indicating that a customer will visit the company today or the next day, retrieves the required details, and sends reminder notifications to the relev
ofn hook v0.24.0 beta. Uses start, httpRequest, functionItem, itemLists. Scheduled trigger; 42 nodes.
Security teams, DevOps engineers, vulnerability analysts, and automation builders who want to eliminate repetitive Nessus scan parsing, AI-based risk triage, and manual reporting. Designed for orgs fo