{
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "name": "Batch-classify & score scraped data with an LLM \u2192 Google Sheets",
  "nodes": [
    {
      "id": "2ecc26d3-4da9-4cfd-9ef2-52d4ef1ef4e0",
      "name": "When clicking Test",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        240,
        300
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "07a18a92-4c13-4d3a-a725-ad4c7d069fcf",
      "name": "Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        460,
        300
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "bde88599-1a94-49c4-89c3-f70cc698508a",
              "name": "upstream_dataset_id",
              "type": "string",
              "value": "REPLACE_WITH_YOUR_APIFY_DATASET_ID"
            },
            {
              "id": "c5599341-0000-449b-884f-c0773011ed72",
              "name": "sheet_document_id",
              "type": "string",
              "value": "REPLACE_WITH_GOOGLE_SHEET_ID"
            },
            {
              "id": "817efcdc-b9e3-4b36-b329-f4c1049adb89",
              "name": "openai_model",
              "type": "string",
              "value": "gpt-4o-mini"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "06eadb32-61ae-4748-b050-70da41bbc1e5",
      "name": "Classify rows with LLM (Apify)",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        700,
        300
      ],
      "parameters": {
        "actorId": {
          "__rl": true,
          "mode": "list",
          "value": "glueworks~llm-dataset-processor",
          "cachedResultUrl": "https://console.apify.com/actors/glueworks~llm-dataset-processor/input",
          "cachedResultName": "glueworks/llm-dataset-processor"
        },
        "timeout": {},
        "customBody": "={\n  \"datasetId\": \"{{ $json.upstream_dataset_id }}\",\n  \"mode\": \"classify\",\n  \"prompt\": \"Classify this item into exactly one category: LEAD, SPAM, or NEUTRAL. Item: {{_json}}\",\n  \"provider\": \"openai\",\n  \"model\": \"{{ $json.openai_model }}\",\n  \"outputField\": \"category\",\n  \"maxItems\": 1000,\n  \"concurrency\": 4\n}",
        "actorSource": "store",
        "waitForFinish": true
      },
      "credentials": {
        "apifyApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "db68e8f4-a385-48b0-80b6-d5c161d42527",
      "name": "Get processed rows",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        920,
        300
      ],
      "parameters": {
        "limit": {},
        "offset": {},
        "resource": "Datasets",
        "datasetId": "={{ $json.defaultDatasetId }}",
        "operation": "Get items"
      },
      "credentials": {
        "apifyApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7d06784b-4828-4b4f-94aa-06983fbb34c4",
      "name": "Save to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1140,
        300
      ],
      "parameters": {
        "columns": {
          "value": {
            "id": "={{ $json.id }}",
            "url": "={{ $json.url }}",
            "title": "={{ $json.title }}",
            "category": "={{ $json.category }}"
          },
          "schema": [
            {
              "id": "id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "url",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "category",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "category",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ]
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "Sheet1",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Configuration').first().json.sheet_document_id }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "f2dc81e2-4859-49ee-8af7-d23ffeeecc1b",
      "name": "note-title",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        -60
      ],
      "parameters": {
        "color": 4,
        "width": 900,
        "height": 300,
        "content": "# Batch-classify scraped data with an LLM \u2192 Google Sheets\n\nTakes the dataset from ANY upstream Apify scraper, classifies/scores/labels every row with an LLM using **glueworks/llm-dataset-processor**, and upserts the results into a Google Sheet.\n\n**Setup:** add Apify + Google Sheets credentials, paste your upstream dataset ID and Sheet ID into the Configuration node, edit the classification prompt."
      },
      "typeVersion": 1
    },
    {
      "id": "dbef0566-4a08-4831-ae0e-fbdbdb6feb0a",
      "name": "note-1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        560
      ],
      "parameters": {
        "color": 7,
        "width": 440,
        "height": 220,
        "content": "## 1. Point at your scraped data\nPut the **dataset ID** of any Apify scraper run (Google Maps, LinkedIn, Instagram, your own crawler\u2026) into the Configuration node. This template is the AI 'downstream' stage."
      },
      "typeVersion": 1
    },
    {
      "id": "dcf1656f-2045-4912-852d-676aac45e851",
      "name": "note-2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        700,
        560
      ],
      "parameters": {
        "color": 7,
        "width": 440,
        "height": 240,
        "content": "## 2. LLM processes every row\nThe Actor runs your prompt over each row (modes: classify / score / extract / rewrite / custom). Result is written to a new field (`category` here). `{{field}}` / `{{_json}}` inject row values into the prompt."
      },
      "typeVersion": 1
    },
    {
      "id": "48cad57d-c475-4eb9-8b1f-a8da9bef2000",
      "name": "note-3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1140,
        560
      ],
      "parameters": {
        "color": 7,
        "width": 360,
        "height": 200,
        "content": "## 3. Upsert to Sheets\nappendOrUpdate keyed on `id` so re-runs update rather than duplicate. Point it at Airtable instead if you prefer."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Configuration": {
      "main": [
        [
          {
            "node": "Classify rows with LLM (Apify)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get processed rows": {
      "main": [
        [
          {
            "node": "Save to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking Test": {
      "main": [
        [
          {
            "node": "Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Classify rows with LLM (Apify)": {
      "main": [
        [
          {
            "node": "Get processed rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}