Migration automatisée de contenu des documents ClickUp vers les enregistrements Airtable

Avancé

Ceci est unContent Creation, Multimodal AIworkflow d'automatisation du domainecontenant 16 nœuds.Utilise principalement des nœuds comme Code, ClickUp, Airtable, HttpRequest, ClickUpTrigger. Automatisation de la migration de contenu de ClickUp vers Airtable

Prérequis
  • Clé API Airtable
  • Peut nécessiter les informations d'identification d'authentification de l'API cible
Aperçu du workflow
Visualisation des connexions entre les nœuds, avec support du zoom et du déplacement
Exporter le workflow
Copiez la configuration JSON suivante dans n8n pour importer et utiliser ce workflow
{
  "meta": {
    "instanceId": "43bcb00c7c923df4e36c0bf713549f86f2dbcd6776a5aa1796b3cf9b1cdd7b7e"
  },
  "nodes": [
    {
      "id": "54d8ddeb-a96a-45d9-82f6-092f4fe2b738",
      "name": "Boucler sur les pages",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -368,
        224
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "cacb5309-604f-43d1-b173-d99268f2571d",
      "name": "Obtenir toutes les bases",
      "type": "n8n-nodes-base.airtable",
      "position": [
        -144,
        144
      ],
      "parameters": {
        "options": {},
        "resource": "base"
      },
      "credentials": {
        "airtableTokenApi": {
          "id": "g8X0PZu8dIVZ4LyX",
          "name": "Airtable Personal Access Token account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "0372b7b0-5c72-437d-afcb-669b2b28bd26",
      "name": "Déclencheur sur nouvelle tâche ClickUp",
      "type": "n8n-nodes-base.clickUpTrigger",
      "position": [
        -1712,
        224
      ],
      "webhookId": "ffa9e6e1-45a2-4be0-93c8-1435de0bd7cf",
      "parameters": {
        "team": "9014329600",
        "events": [
          "taskCreated"
        ],
        "filters": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "clickUpOAuth2Api": {
          "id": "cpNaV1HxXYDutqlG",
          "name": "ClickUp account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "db22385e-cd6a-4b74-83d1-7cd81ec46666",
      "name": "Obtenir les détails de la tâche",
      "type": "n8n-nodes-base.clickUp",
      "position": [
        -1456,
        224
      ],
      "parameters": {
        "id": "={{ $json.task_id }}",
        "operation": "get",
        "authentication": "oAuth2"
      },
      "credentials": {
        "clickUpOAuth2Api": {
          "id": "cpNaV1HxXYDutqlG",
          "name": "ClickUp account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2794d633-ffd8-4821-abca-0b82858a0852",
      "name": "Extraire les IDs de document et d'espace de travail de l'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": "Obtenir les détails du document ClickUp",
      "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": {
          "id": "cpNaV1HxXYDutqlG",
          "name": "ClickUp account"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "b80b1a8d-c8dd-4f62-8475-850408a43abb",
      "name": "Récupérer toutes les pages du document",
      "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": {
          "id": "cpNaV1HxXYDutqlG",
          "name": "ClickUp account"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "ae7a5381-c1de-4417-9472-fc7478b1bdab",
      "name": "Extraire le contenu des pages du document",
      "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": "Faire correspondre la base Airtable par nom",
      "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": "Obtenir toutes les tables dans la base sélectionnée",
      "type": "n8n-nodes-base.airtable",
      "position": [
        304,
        144
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "resource": "base",
        "operation": "getSchema"
      },
      "credentials": {
        "airtableTokenApi": {
          "id": "g8X0PZu8dIVZ4LyX",
          "name": "Airtable Personal Access Token account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "fdc103b4-55a5-401d-93d9-31a586527e9c",
      "name": "Faire correspondre la table Airtable par nom",
      "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": "Trouver l'enregistrement \"Vertical\" correspondant",
      "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": {
          "id": "g8X0PZu8dIVZ4LyX",
          "name": "Airtable Personal Access Token account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "74d12946-602f-4064-927f-e3be32329a3a",
      "name": "Créer un nouvel enregistrement dans 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": {
          "id": "g8X0PZu8dIVZ4LyX",
          "name": "Airtable Personal Access Token account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "a65db100-fb6b-46c0-b69f-8b005428e1c6",
      "name": "Note adhésive",
      "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": "Note adhésive 1",
      "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": "Note adhésive 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        80
      ],
      "parameters": {
        "color": 4,
        "width": 1360,
        "height": 352,
        "content": "## Move Everything to Airtable\n"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "cacb5309-604f-43d1-b173-d99268f2571d": {
      "main": [
        [
          {
            "node": "9c8d6ff9-3f60-4576-886a-6ac21a38e247",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "54d8ddeb-a96a-45d9-82f6-092f4fe2b738": {
      "main": [
        [],
        [
          {
            "node": "cacb5309-604f-43d1-b173-d99268f2571d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "db22385e-cd6a-4b74-83d1-7cd81ec46666": {
      "main": [
        [
          {
            "node": "2794d633-ffd8-4821-abca-0b82858a0852",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b80b1a8d-c8dd-4f62-8475-850408a43abb": {
      "main": [
        [
          {
            "node": "ae7a5381-c1de-4417-9472-fc7478b1bdab",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "323e614d-7ad9-4265-8981-0cd444a42a67": {
      "main": [
        [
          {
            "node": "b80b1a8d-c8dd-4f62-8475-850408a43abb",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "9c8d6ff9-3f60-4576-886a-6ac21a38e247": {
      "main": [
        [
          {
            "node": "48f0e7b2-eb72-424f-9525-49777ca4dbdf",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "0372b7b0-5c72-437d-afcb-669b2b28bd26": {
      "main": [
        [
          {
            "node": "db22385e-cd6a-4b74-83d1-7cd81ec46666",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "fdc103b4-55a5-401d-93d9-31a586527e9c": {
      "main": [
        [
          {
            "node": "b55b9fb5-3457-4eb0-8d8c-8ec5c0ef68cf",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ae7a5381-c1de-4417-9472-fc7478b1bdab": {
      "main": [
        [
          {
            "node": "54d8ddeb-a96a-45d9-82f6-092f4fe2b738",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "74d12946-602f-4064-927f-e3be32329a3a": {
      "main": [
        [
          {
            "node": "54d8ddeb-a96a-45d9-82f6-092f4fe2b738",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "48f0e7b2-eb72-424f-9525-49777ca4dbdf": {
      "main": [
        [
          {
            "node": "fdc103b4-55a5-401d-93d9-31a586527e9c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2794d633-ffd8-4821-abca-0b82858a0852": {
      "main": [
        [
          {
            "node": "323e614d-7ad9-4265-8981-0cd444a42a67",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b55b9fb5-3457-4eb0-8d8c-8ec5c0ef68cf": {
      "main": [
        [
          {
            "node": "74d12946-602f-4064-927f-e3be32329a3a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Foire aux questions

Comment utiliser ce workflow ?

Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.

Dans quelles scénarios ce workflow est-il adapté ?

Avancé - Création de contenu, IA Multimodale

Est-ce payant ?

Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.

Informations sur le workflow
Niveau de difficulté
Avancé
Nombre de nœuds16
Catégorie2
Types de nœuds7
Description de la difficulté

Adapté aux utilisateurs avancés, avec des workflows complexes contenant 16+ nœuds

Auteur
Fahmi Fahreza

Fahmi Fahreza

@fahmiiireza

Backend Developer turns to AI Automation Developer

Liens externes
Voir sur n8n.io

Partager ce workflow

Catégories

Catégories: 34