AutomationFlowsData & Sheets › Automated Content Migration From Clickup Docs to Airtable Records

Automated Content Migration From Clickup Docs to Airtable Records

ByFahmi Fahreza @fahmiiireza on n8n.io

This workflow automates the process of turning content from ClickUp Docs into structured data in Airtable. When a new task is created in ClickUp with a link to a ClickUp Doc in its name, this workflow triggers, fetches the entire content of that Doc, parses it into individual…

Event trigger★★★★☆ complexity16 nodesAirtableClickUp TriggerClickUpHTTP Request
Data & Sheets Trigger: Event Nodes: 16 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #9135 — we link there as the canonical source.

This workflow follows the Airtable → 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 →

Download .json
{
  "nodes": [
    {
      "id": "54d8ddeb-a96a-45d9-82f6-092f4fe2b738",
      "name": "Loop Over Pages",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -368,
        224
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "cacb5309-604f-43d1-b173-d99268f2571d",
      "name": "Get All Base",
      "type": "n8n-nodes-base.airtable",
      "position": [
        -144,
        144
      ],
      "parameters": {
        "options": {},
        "resource": "base"
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "0372b7b0-5c72-437d-afcb-669b2b28bd26",
      "name": "Trigger on New Clickup Task",
      "type": "n8n-nodes-base.clickUpTrigger",
      "position": [
        -1712,
        224
      ],
      "parameters": {
        "team": "9014329600",
        "events": [
          "taskCreated"
        ],
        "filters": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "clickUpOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "db22385e-cd6a-4b74-83d1-7cd81ec46666",
      "name": "Get Task Details",
      "type": "n8n-nodes-base.clickUp",
      "position": [
        -1456,
        224
      ],
      "parameters": {
        "id": "={{ $json.task_id }}",
        "operation": "get",
        "authentication": "oAuth2"
      },
      "credentials": {
        "clickUpOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2794d633-ffd8-4821-abca-0b82858a0852",
      "name": "Extract Doc & Workspace IDs from URL",
      "type": "n8n-nodes-base.code",
      "position": [
        -1248,
        224
      ],
      "parameters": {
        "jsCode": "const results = [];\n\nfor (const item of $input.all()) {\n  const url = item.json.name;\n\n  const regex = /clickup\\.com\\/(\\d+)\\/v\\/dc\\/([^/]+)/;\n  const match = url.match(regex);\n\n  if (match) {\n    results.push({\n      json: {\n        clickupUrl: url,\n        workspaceId: match[1],\n        docId: match[2],\n      }\n    });\n  }\n}\n\nreturn results;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "323e614d-7ad9-4265-8981-0cd444a42a67",
      "name": "Get ClickUp Doc Details",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1024,
        224
      ],
      "parameters": {
        "url": "=https://api.clickup.com/api/v3/workspaces/{{$json.workspaceId}}/docs/{{$json.docId}}",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "max_page_depth",
              "value": "-2"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "accept",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "clickUpApi"
      },
      "credentials": {
        "clickUpOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "b80b1a8d-c8dd-4f62-8475-850408a43abb",
      "name": "Fetch All Pages in Doc",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -800,
        224
      ],
      "parameters": {
        "url": "=https://api.clickup.com/api/v3/workspaces/{{$json.workspace_id}}/docs/{{$json.id}}/pages",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "max_page_depth",
              "value": "-2"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "accept",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "clickUpOAuth2Api"
      },
      "credentials": {
        "clickUpOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "ae7a5381-c1de-4417-9472-fc7478b1bdab",
      "name": "Parse Content from Doc Pages",
      "type": "n8n-nodes-base.code",
      "position": [
        -576,
        224
      ],
      "parameters": {
        "jsCode": "const output = [];\n\nfor (const item of $input.all()) {\n  const pages = item.json.pages || [];\n  const tableName = item.json.name;\n  const baseName = $('Get ClickUp Doc Details').first().json.name;\n\n  for (const page of pages) {\n    const rawContent = page.content || \"\";\n    const content = rawContent.trim();\n\n    if (content.includes(\"* * *\")) {\n      const splitContents = content.split(\"* * *\");\n\n      for (const part of splitContents) {\n        const trimmed = part.trim();\n        if (!trimmed) continue;\n\n        let contentText = trimmed;\n        let notesText = \"\";\n\n        if (trimmed.toLowerCase().includes(\"notes:\")) {\n          const [main, ...notesParts] = trimmed.split(/notes:/i);\n          contentText = main.trim();\n          notesText = notesParts.join(\"notes:\").trim();\n        }\n\n        // Remove all '*' and re-trim\n        contentText = contentText.replace(/\\*/g, '').trim();\n\n        output.push({\n          json: {\n            base: baseName,\n            table: tableName,\n            name: page.name,\n            content: contentText,\n            notes: notesText\n          }\n        });\n      }\n    } else {\n      let contentText = content;\n      let notesText = \"\";\n\n      if (content.toLowerCase().includes(\"notes:\")) {\n        const [main, ...notesParts] = content.split(/notes:/i);\n        contentText = main.trim();\n        notesText = notesParts.join(\"notes:\").trim();\n      }\n\n      // Remove all '*' and re-trim\n      contentText = contentText.replace(/\\*/g, '').trim();\n\n      output.push({\n        json: {\n          base: baseName,\n          table: tableName,\n          name: page.name,\n          content: contentText,\n          notes: notesText\n        }\n      });\n    }\n  }\n}\n\nreturn output;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "9c8d6ff9-3f60-4576-886a-6ac21a38e247",
      "name": "Match Airtable Base by Name",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        144
      ],
      "parameters": {
        "jsCode": "const baseRaw = $('Loop Over Pages').first().json.base.trim().toLowerCase();\nconst base = baseRaw.endsWith(' (new)')\n  ? baseRaw.slice(0, -6)\n  : baseRaw;\n\n\n\nconst output = [];\n\nfor (const item of $input.all()) {\nlet itemNameRaw = item.json.name?.trim().toLowerCase();\nconst itemName = itemNameRaw?.endsWith(' (new)')\n  ? itemNameRaw.slice(0, -6)\n  : itemNameRaw;\n  if (base === itemName) {\n    output.push(item);\n  }\n}\n\nreturn output;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "48f0e7b2-eb72-424f-9525-49777ca4dbdf",
      "name": "Get All Tables in Selected Base",
      "type": "n8n-nodes-base.airtable",
      "position": [
        304,
        144
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "resource": "base",
        "operation": "getSchema"
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "fdc103b4-55a5-401d-93d9-31a586527e9c",
      "name": "Match Airtable Table by Name",
      "type": "n8n-nodes-base.code",
      "position": [
        528,
        144
      ],
      "parameters": {
        "jsCode": "const table = $('Loop Over Pages').first().json.table.trim().toLowerCase();\n\nconst output = [];\n\nfor (const item of $input.all()) {\n  const itemName = item.json.name?.trim().toLowerCase();\n\n if (table === itemName) {\n    output.push(item);\n  }\n }\n\nreturn output;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "b55b9fb5-3457-4eb0-8d8c-8ec5c0ef68cf",
      "name": "Find Corresponding \"Vertical\" Record",
      "type": "n8n-nodes-base.airtable",
      "position": [
        752,
        144
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Match Airtable Base by Name').item.json.id }}"
        },
        "table": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Get All Tables in Selected Base').first().json.id }}"
        },
        "options": {
          "fields": [
            "Name"
          ]
        },
        "operation": "search",
        "filterByFormula": "={Name} = '{{ $('Loop Over Pages').item.json.name }}'"
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "74d12946-602f-4064-927f-e3be32329a3a",
      "name": "Create New Record in Airtable",
      "type": "n8n-nodes-base.airtable",
      "position": [
        960,
        224
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Match Airtable Base by Name').item.json.id }}"
        },
        "table": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Match Airtable Table by Name').item.json.id }}"
        },
        "columns": {
          "value": {
            "Text": "={{ $('Loop Over Pages').item.json.content }}",
            "Notes": "={{ $('Loop Over Pages').item.json.notes }}",
            "Status": "Testing",
            "Vertical": "={{ $json.Name }}",
            "Created Date": "={{ $now }}"
          },
          "schema": [
            {
              "id": "Text",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Text",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Vertical",
              "type": "array",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Vertical",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "options",
              "display": true,
              "options": [
                {
                  "name": "Testing",
                  "value": "Testing"
                },
                {
                  "name": "Winner",
                  "value": "Winner"
                },
                {
                  "name": "Non-Compliant (Buyer)",
                  "value": "Non-Compliant (Buyer)"
                },
                {
                  "name": "Rejected (FB)",
                  "value": "Rejected (FB)"
                },
                {
                  "name": "Account Mover",
                  "value": "Account Mover"
                },
                {
                  "name": "Loser",
                  "value": "Loser"
                },
                {
                  "name": "Rejected (Appealed)",
                  "value": "Rejected (Appealed)"
                }
              ],
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Notes",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Notes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Created Date",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Created Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "typecast": true
        },
        "operation": "create"
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "a65db100-fb6b-46c0-b69f-8b005428e1c6",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2544,
        -1184
      ],
      "parameters": {
        "width": 688,
        "height": 1264,
        "content": "## Create Airtable records from new ClickUp Doc pages\n\nThis workflow automates the process of turning content from ClickUp Docs into structured data in Airtable. When a new task is created in ClickUp with a link to a ClickUp Doc in its name, this workflow triggers, fetches the entire content of that Doc, parses it into individual records, and then creates a new record for each item in a specified Airtable base and table.\n\n## Who's it for\n\nThis template is perfect for content creators, project managers, and operations teams who use ClickUp Docs for drafting or knowledge management and Airtable for tracking and organizing data. It helps bridge the gap between unstructured text and a structured database.\n\n## How it works\n\n1.  **Trigger:** The workflow starts when a new task is created in a specific ClickUp Team.\n2.  **Fetch & Parse URL:** It gets the new task's details and extracts the ClickUp Doc URL from the task name.\n3.  **Get Doc Content:** It uses the URL to fetch the main Doc and all its sub-pages from the ClickUp API.\n4.  **Process Content:** A Code node parses the text from each page. It's designed to split content by `* * *` and separate notes by looking for the \"notes:\" keyword.\n5.  **Find Airtable Destination:** The workflow finds the correct Airtable Base and Table IDs by matching the names you provide.\n6.  **Create Records:** It loops through each parsed content piece and creates a new record in your specified Airtable table.\n\n## How to set up\n\n1.  **Configure the `Set` Node:** Open the \"Configure Variables\" node and set the following values:\n    * `clickupTeamId`: Your ClickUp Team ID. Find it in your ClickUp URL (e.g., `app.clickup.com/9014329600/...`).\n    * `airtableBaseName`: The exact name of your target Airtable Base.\n    * `airtableTableName`: The exact name of your target Airtable Table.\n    * `airtableVerticalsTableName`: The name of the table in your base that holds \"Vertical\" records, which are linked in the main table.\n2.  **Set Up Credentials:** Add your ClickUp (OAuth2) and Airtable (Personal Access Token) credentials to the respective nodes.\n3.  **Airtable Fields:** Ensure your Airtable table has fields corresponding to the ones in the `Create New Record in Airtable` node (e.g., `Text`, `Status`, `Vertical`, `Notes`). You can customize the mapping in this node.\n4.  **Activate Workflow:** Save and activate the workflow.\n5.  **Test:** Create a new task in your designated ClickUp team. In the task name, include the full URL of the ClickUp Doc you want to process.\n\n## How to customize the workflow\n\n* **Parsing Logic:** You can change how the content is parsed by modifying the JavaScript in the `Parse Content from Doc Pages` Code node. For example, you could change the delimiter from `* * *` to something else.\n* **Field Mapping:** Adjust the `Create New Record in Airtable` node to map data to different fields or add more fields from the source data.\n* **Trigger Events:** Modify the `Trigger on New ClickUp Task` node to respond to different events, such as `taskUpdated` or `taskCommentPosted`."
      },
      "typeVersion": 1
    },
    {
      "id": "d1610a6f-0ed6-4060-a25a-35562abb42ab",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1760,
        128
      ],
      "parameters": {
        "color": 4,
        "width": 1328,
        "height": 256,
        "content": "## Fetch Clickup Task, Doc, and Page Content\n"
      },
      "typeVersion": 1
    },
    {
      "id": "f8ef9da3-4581-4974-9c5d-3fb55cb4cf8c",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        80
      ],
      "parameters": {
        "color": 4,
        "width": 1360,
        "height": 352,
        "content": "## Move Everything to Airtable\n"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Get All Base": {
      "main": [
        [
          {
            "node": "Match Airtable Base by Name",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Pages": {
      "main": [
        [],
        [
          {
            "node": "Get All Base",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Task Details": {
      "main": [
        [
          {
            "node": "Extract Doc & Workspace IDs from URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch All Pages in Doc": {
      "main": [
        [
          {
            "node": "Parse Content from Doc Pages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get ClickUp Doc Details": {
      "main": [
        [
          {
            "node": "Fetch All Pages in Doc",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Match Airtable Base by Name": {
      "main": [
        [
          {
            "node": "Get All Tables in Selected Base",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger on New Clickup Task": {
      "main": [
        [
          {
            "node": "Get Task Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Match Airtable Table by Name": {
      "main": [
        [
          {
            "node": "Find Corresponding \"Vertical\" Record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Content from Doc Pages": {
      "main": [
        [
          {
            "node": "Loop Over Pages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create New Record in Airtable": {
      "main": [
        [
          {
            "node": "Loop Over Pages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get All Tables in Selected Base": {
      "main": [
        [
          {
            "node": "Match Airtable Table by Name",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Doc & Workspace IDs from URL": {
      "main": [
        [
          {
            "node": "Get ClickUp Doc Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find Corresponding \"Vertical\" Record": {
      "main": [
        [
          {
            "node": "Create New Record in Airtable",
            "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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow automates the process of turning content from ClickUp Docs into structured data in Airtable. When a new task is created in ClickUp with a link to a ClickUp Doc in its name, this workflow triggers, fetches the entire content of that Doc, parses it into individual…

Source: https://n8n.io/workflows/9135/ — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

Lmchatopenai Workflow. Uses noOp, stickyNote, executeWorkflowTrigger, airtable. Event-driven trigger; 41 nodes.

Execute Workflow Trigger, Airtable, HTTP Request
Data & Sheets

This n8n workflow retrieves an Airtable record along with its related child records in a hierarchical structure. It can fetch up to 3 levels of linked records and assembles them into a comprehensive J

Execute Workflow Trigger, Airtable, HTTP Request
Data & Sheets

How it works

Airtable Trigger, Sendinblue, Airtable +1
Data & Sheets

This workflow automatically pulls SERP rankings, competitor keywords, and related keyword ideas from DataForSEO and stores structured results in Airtable — making SEO tracking and keyword research str

Airtable, HTTP Request
Data & Sheets

d16-Web-Scraper-Data-Flow. Uses httpRequest, airtable, executeWorkflowTrigger. Event-driven trigger; 20 nodes.

HTTP Request, Airtable, Execute Workflow Trigger