AutomationFlowsWeb Scraping › [chatbot] Docs Sync

[chatbot] Docs Sync

[Chatbot] Docs Sync. Uses httpRequest. Scheduled trigger; 10 nodes.

Cron / scheduled trigger★★★★☆ complexity10 nodesHTTP Request
Web Scraping Trigger: Cron / scheduled Nodes: 10 Complexity: ★★★★☆ Added:

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
{
  "name": "[Chatbot] Docs Sync",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 30
            }
          ]
        }
      },
      "id": "schedule-trigger",
      "name": "Every 30 Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        100,
        300
      ]
    },
    {
      "parameters": {},
      "id": "manual-trigger",
      "name": "Manual Sync",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        100,
        450
      ]
    },
    {
      "id": "list-drive-files",
      "name": "List Drive Files",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        320,
        370
      ],
      "parameters": {
        "method": "GET",
        "url": "https://dabbahwala-latest.onrender.com/api/internal/drive/files",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "split-files",
      "name": "Split Files",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        540,
        370
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nreturn (data.files || []).map(f => ({json: f}));"
      }
    },
    {
      "parameters": {
        "jsCode": "// Filter to only Google Docs and classify by title pattern\nconst doc = $input.item.json;\n\nif (doc.mimeType !== 'application/vnd.google-apps.document') {\n  return [];\n}\n\nlet content_type = 'ground_note';\nconst titleLower = (doc.name || '').toLowerCase();\n\nif (titleLower.includes('ad copy') || titleLower.includes('ad_copy') ||\n    titleLower.includes('social media') || titleLower.includes('facebook') ||\n    titleLower.includes('instagram') || titleLower.includes('social post')) {\n  content_type = 'ad_copy';\n} else if (titleLower.includes('field note') || titleLower.includes('ground') ||\n           titleLower.includes('delivery note') || titleLower.includes('driver')) {\n  content_type = 'ground_note';\n}\n\nreturn [{\n  json: {\n    google_doc_id: doc.id,\n    title: doc.name,\n    content_type,\n    google_last_modified: doc.modifiedTime,\n    author: doc.lastModifyingUser?.displayName || 'Unknown',\n    doc_url: `https://docs.google.com/document/d/${doc.id}/edit`\n  }\n}];"
      },
      "id": "classify-files",
      "name": "Filter & Classify",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        760,
        370
      ]
    },
    {
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "id": "not-empty",
              "leftValue": "={{ $json._empty }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "notEqual"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "has-docs",
      "name": "Has Docs?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        980,
        370
      ]
    },
    {
      "id": "read-doc",
      "name": "Read Google Doc",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1200,
        270
      ],
      "parameters": {
        "method": "GET",
        "url": "=https://dabbahwala-latest.onrender.com/api/internal/docs/{{ $json.google_doc_id }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const docContent = $input.first().json;\nlet textContent = '';\ntry {\n  if (docContent.text) {\n    textContent = docContent.text;\n  } else if (docContent.body && docContent.body.content) {\n    textContent = docContent.body.content.map(block => {\n      if (block.paragraph) {\n        return block.paragraph.elements?.map(el => el.textRun?.content || '').join('');\n      }\n      return '';\n    }).join('');\n  } else {\n    textContent = JSON.stringify(docContent).substring(0, 5000);\n  }\n} catch (e) {\n  textContent = 'Error extracting content: ' + e.message;\n}\n\nconst meta = $('Filter & Classify').item.json;\n\nreturn [{\n  json: {\n    google_doc_id: meta.google_doc_id,\n    content_type: meta.content_type,\n    title: meta.title,\n    body: textContent.trim(),\n    author: meta.author,\n    google_last_modified: meta.google_last_modified,\n    doc_url: meta.doc_url,\n    tags: []\n  }\n}];"
      },
      "id": "build-payload",
      "name": "Build Document Payload",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1420,
        270
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://dabbahwala-latest.onrender.com/api/team-content/sync",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ documents: [$json] }) }}",
        "options": {
          "timeout": 30000
        }
      },
      "id": "sync-to-api",
      "name": "Sync to API",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1640,
        270
      ],
      "continueOnFail": true
    },
    {
      "parameters": {},
      "id": "no-docs",
      "name": "No New Docs \u2014 Skip",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1200,
        480
      ]
    }
  ],
  "connections": {
    "Every 30 Minutes": {
      "main": [
        [
          {
            "node": "List Drive Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Sync": {
      "main": [
        [
          {
            "node": "List Drive Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List Drive Files": {
      "main": [
        [
          {
            "node": "Split Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Files": {
      "main": [
        [
          {
            "node": "Filter & Classify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter & Classify": {
      "main": [
        [
          {
            "node": "Has Docs?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Docs?": {
      "main": [
        [
          {
            "node": "Read Google Doc",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No New Docs \u2014 Skip",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Google Doc": {
      "main": [
        [
          {
            "node": "Build Document Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Document Payload": {
      "main": [
        [
          {
            "node": "Sync to API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}

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

[Chatbot] Docs Sync. Uses httpRequest. Scheduled trigger; 10 nodes.

Source: https://github.com/vivek-dataskate/DabbahWala/blob/55df577abf41d0b89f3199f4c78662a9513accba/n8n/google_docs_sync.json — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

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

Web Scraping

Birthday Automation - Production (Fixed). Uses stopAndError, httpRequest, emailSend, bannerbear. Scheduled trigger; 86 nodes.

Stop And Error, HTTP Request, Email Send +1
Web Scraping

This template runs two scheduled workflows to govern Microsoft Entra ID (Azure AD) guest accounts by detecting stale users via Microsoft Graph, staging deletions in SharePoint with a 72-hour window, n

Microsoft SharePoint, Microsoft Teams, Microsoft Entra +1
Web Scraping

Jira-Allure-Auto-Qa. Uses httpRequest, jira. Scheduled trigger; 68 nodes.

HTTP Request, Jira
Web Scraping

Spotify-Sync-Surrealdb-V1. Uses httpRequest, n8n-nodes-surrealdb, spotify. Scheduled trigger; 62 nodes.

HTTP Request, N8N Nodes Surrealdb, Spotify
Web Scraping

As n8n instances scale, teams often lose track of sub-workflows—who uses them, where they are referenced, and whether they can be safely updated. This leads to inefficiencies like unnecessary copies o

HTTP Request, n8n, N8N Trigger +1