AutomationFlowsWeb Scraping › Bulk Import Local PDF and Text Files Into an Open Notebook Notebook

Bulk Import Local PDF and Text Files Into an Open Notebook Notebook

By池田 誠 @gensekikobo on n8n.io

This self-hosted n8n workflow scans a local folder for PDF and TXT files and bulk imports them into an Open Notebook notebook via its API, uploading PDFs as files and sending text files as JSON content. Runs manually when you start the workflow. Calls the Open Notebook API to…

Event trigger★★★★☆ complexity13 nodesHTTP RequestExecute Command
Web Scraping Trigger: Event Nodes: 13 Complexity: ★★★★☆ Added:

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

This workflow follows the Executecommand → 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
{
  "name": "Bulk import PDF and TXT files from a folder into Open Notebook",
  "nodes": [
    {
      "id": "8cedb6ba-8e60-48cf-9aaf-e7065f94d0e0",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        144
      ],
      "parameters": {
        "color": 1,
        "width": 480,
        "height": 900,
        "content": "## Bulk import PDF and TXT files from a folder into Open Notebook\n\n**Self-hosted n8n only.** This template uses the *Execute Command* node (shell + local filesystem access), which is not available on n8n Cloud.\n\n### How it works\nRuns on demand to bulk import local PDF and TXT files into a chosen Open Notebook notebook. It reads the folder, notebook name and API base URL from one config step, resolves the target notebook ID through the Open Notebook API, discovers matching files, then loops through them one at a time. PDFs are uploaded as files; text files are sent as JSON content.\n\n### How to set up\n1. In Open Notebook, create the notebook you want to import into.\n2. Open **Set Folder and Notebook Config** and fill in the three values:\n   - `folder_in` - the folder to scan\n   - `notebook_name` - must match the notebook name exactly\n   - `api_base` - your Open Notebook API URL (default `http://localhost:5055/api`)\n3. Click **Trigger on Demand** to execute.\n\n### Requirements\n- Self-hosted n8n with the Execute Command node enabled\n- `curl` and `python3` (with the `requests` package) on the n8n host\n- A running Open Notebook instance reachable from n8n\n- Read access to the folder holding the `.pdf` and `.txt` files\n\n### Customize\nSwap **Trigger on Demand** for a Schedule Trigger to import automatically, edit the `find` command to include more file types, or change the batch size on the loop node."
      },
      "typeVersion": 1
    },
    {
      "id": "6c25fc55-9e1c-4fc6-9b68-4cc5bdbd4901",
      "name": "Note - Step 1 Configure",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        512,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 320,
        "content": "## Manual run configuration\n\nStarts the workflow manually and defines the folder, notebook name, and Open Notebook API base URL used by the rest of the workflow."
      },
      "typeVersion": 1
    },
    {
      "id": "a34b9ff5-63ee-4498-9bd6-348a0c609e0a",
      "name": "Note - Step 2 Resolve notebook",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1120,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 320,
        "content": "## Resolve target notebook\n\nFetches the available notebooks from Open Notebook and uses custom code to identify the ID for the configured notebook name."
      },
      "typeVersion": 1
    },
    {
      "id": "f4b32d8c-1587-4089-9593-710c5cfa8bf4",
      "name": "Note - Step 3 Collect files",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1712,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 320,
        "content": "## Discover import files\n\nSearches the configured folder for TXT and PDF files, then converts the command output into individual file items for processing."
      },
      "typeVersion": 1
    },
    {
      "id": "b8cb7fe5-4617-4058-83e3-c348d9df3c77",
      "name": "Note - Step 4 Upload loop",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2320,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 320,
        "content": "## Loop and upload files\n\nIterates over each prepared file item and uploads it to the resolved Open Notebook notebook, looping back until all files are processed."
      },
      "typeVersion": 1
    },
    {
      "id": "5c270987-211a-43a8-9b5e-9cfb91d40659",
      "name": "Trigger on Demand",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        560,
        304
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "06abd68a-77e2-4e6f-81d7-c66e77c8257a",
      "name": "Set Folder and Notebook Config",
      "type": "n8n-nodes-base.set",
      "position": [
        864,
        304
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-folder",
              "name": "folder_in",
              "type": "string",
              "value": "/path/to/your/folder"
            },
            {
              "id": "cfg-notebook",
              "name": "notebook_name",
              "type": "string",
              "value": "My Notebook"
            },
            {
              "id": "cfg-api",
              "name": "api_base",
              "type": "string",
              "value": "http://localhost:5055/api"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "cfd2415a-29d4-4820-83d1-7e27694ea8cf",
      "name": "Fetch Notebooks List",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1168,
        304
      ],
      "parameters": {
        "url": "={{ $json.api_base }}/notebooks",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "df6048a2-8492-4a2c-b16c-c4d7fe6c7732",
      "name": "Resolve Target Notebook ID",
      "type": "n8n-nodes-base.code",
      "position": [
        1472,
        304
      ],
      "parameters": {
        "jsCode": "const notebooks = $input.all().map(i => i.json);\nconst cfg = $('Set Folder and Notebook Config').first().json;\nconst match = notebooks.find(n => n.name === cfg.notebook_name);\n\nif (!match) {\n  throw new Error(`Notebook \"${cfg.notebook_name}\" was not found. Please create it in the Open Notebook UI first, then run again.`);\n}\n\nreturn [{\n  json: {\n    notebook_id: match.id,\n    folder_in: cfg.folder_in,\n    api_base: cfg.api_base\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "324761f0-9a77-484b-a8bf-c65105d21836",
      "name": "Locate TXT and PDF Files",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        1760,
        304
      ],
      "parameters": {
        "command": "=find \"{{ $json.folder_in }}\" -type f \\( -iname \"*.txt\" -o -iname \"*.pdf\" \\)"
      },
      "typeVersion": 1
    },
    {
      "id": "1c9cf207-d0d0-4c88-8e9c-148ffacf575a",
      "name": "Prepare File Items",
      "type": "n8n-nodes-base.code",
      "position": [
        2064,
        304
      ],
      "parameters": {
        "jsCode": "const stdout = $input.first().json.stdout || '';\nconst files = stdout.split('\\n').map(s => s.trim()).filter(s => s.length > 0);\nconst prev = $('Resolve Target Notebook ID').first().json;\n\n// Wraps a value in single quotes so the shell treats it literally.\n// Any embedded single quote is closed, escaped and reopened: ' -> '\\''\nconst shellQuote = (v) => \"'\" + String(v).replace(/'/g, \"'\\\\''\") + \"'\";\n\nreturn files.map(filePath => {\n  const parts = filePath.split('/');\n  const fileName = parts.pop();\n  const dotIndex = fileName.lastIndexOf('.');\n  const title = dotIndex > -1 ? fileName.substring(0, dotIndex) : fileName;\n  const ext = dotIndex > -1\n    ? fileName.substring(dotIndex + 1).toLowerCase().replace(/[^a-z0-9]/g, '')\n    : '';\n  return {\n    json: {\n      file_path: filePath,\n      title,\n      ext,\n      notebook_id: prev.notebook_id,\n      api_base: prev.api_base,\n      // Shell-safe variants consumed by the Execute Command node.\n      // Keeps file names containing \" ` $ \\ or ' from breaking the command.\n      file_path_sh: shellQuote(filePath),\n      title_sh: shellQuote(title)\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "1993af8d-5d32-4e6b-9e36-ac77dcade0ea",
      "name": "Batch File Processing",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        2368,
        304
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "12f57f37-e101-4b57-a254-ca41e897e323",
      "name": "Upload Files to Notebook",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        2672,
        304
      ],
      "parameters": {
        "command": "=ext=\"{{ $json.ext }}\"\nfile_path={{ $json.file_path_sh }}\ntitle={{ $json.title_sh }}\nnotebook_id=\"{{ $json.notebook_id }}\"\napi_base=\"{{ $json.api_base }}\"\n\nif [ \"$ext\" = \"pdf\" ]; then\n  curl -s -X POST \"$api_base/sources\" \\\n    -F \"type=upload\" \\\n    -F \"title=$title\" \\\n    -F \"notebooks=[\\\"$notebook_id\\\"]\" \\\n    -F \"async_processing=true\" \\\n    -F \"file=@$file_path\"\nelse\n  python3 -c \"\nimport json, sys, requests\nwith open(sys.argv[1], encoding='utf-8', errors='ignore') as f:\n    content = f.read()\npayload = {\n    'type': 'text',\n    'content': content,\n    'title': sys.argv[2],\n    'notebooks': [sys.argv[3]],\n    'async_processing': True,\n}\nr = requests.post(sys.argv[4] + '/sources/json', json=payload)\nprint(r.status_code, r.text[:300])\n\" \"$file_path\" \"$title\" \"$notebook_id\" \"$api_base\"\nfi"
      },
      "executeOnce": false,
      "typeVersion": 1,
      "alwaysOutputData": false
    }
  ],
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "connections": {
    "Trigger on Demand": {
      "main": [
        [
          {
            "node": "Set Folder and Notebook Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare File Items": {
      "main": [
        [
          {
            "node": "Batch File Processing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Notebooks List": {
      "main": [
        [
          {
            "node": "Resolve Target Notebook ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Batch File Processing": {
      "main": [
        [],
        [
          {
            "node": "Upload Files to Notebook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Locate TXT and PDF Files": {
      "main": [
        [
          {
            "node": "Prepare File Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Files to Notebook": {
      "main": [
        [
          {
            "node": "Batch File Processing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Resolve Target Notebook ID": {
      "main": [
        [
          {
            "node": "Locate TXT and PDF Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Folder and Notebook Config": {
      "main": [
        [
          {
            "node": "Fetch Notebooks List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

This self-hosted n8n workflow scans a local folder for PDF and TXT files and bulk imports them into an Open Notebook notebook via its API, uploading PDFs as files and sending text files as JSON content. Runs manually when you start the workflow. Calls the Open Notebook API to…

Source: https://n8n.io/workflows/17680/ — 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

This workflow allows you to import any workflow from a file or another n8n instance and map the credentials easily. A multi-form setup guides you through the entire process At the beginning you have t

Execute Command, Read Write File, HTTP Request +3
Web Scraping

Backup Credentials to GitHub. Uses httpRequest, github, executeCommand, executeWorkflowTrigger. Event-driven trigger; 25 nodes.

HTTP Request, GitHub, Execute Command +1
Web Scraping

Based on Jonathan's work. Check out his templates.

HTTP Request, GitHub, Execute Command +1
Web Scraping

Backup your credentials to GitHub. Uses httpRequest, github, executeCommand, executeWorkflowTrigger. Event-driven trigger; 24 nodes.

HTTP Request, GitHub, Execute Command +1
Web Scraping

extract_swifts. Uses manualTrigger, httpRequest, htmlExtract, splitInBatches. Event-driven trigger; 23 nodes.

HTTP Request, Html Extract, MongoDB +5