AutomationFlowsData & Sheets › Classify Event Photos From Attendees with Gemma Ai, Google Drive & Sheets

Classify Event Photos From Attendees with Gemma Ai, Google Drive & Sheets

ByJimleuk @jimleuk on n8n.io

n8n can indeed help to solve this challenge by providing the data input interface via its forms and orchestrate AI-powered classification of images using AI nodes. However, in some cases - say you run regular events or with high attendee counts - the volume of photos may result…

Event trigger★★★★☆ complexity20 nodesForm TriggerHTTP RequestGoogle DriveEdit ImageGoogle Sheets
Data & Sheets Trigger: Event Nodes: 20 Complexity: ★★★★☆ Added:

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

This workflow follows the Editimage → 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
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "8c27dc47-c6fc-4057-965f-3a6b98c5c8d0",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -1360,
        272
      ],
      "parameters": {
        "options": {
          "ignoreBots": true,
          "buttonLabel": "Upload",
          "appendAttribution": false
        },
        "formTitle": "Photo Uploads",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Name",
              "requiredField": true
            },
            {
              "fieldType": "file",
              "fieldLabel": "Files",
              "requiredField": true,
              "acceptFileTypes": "jpg,png"
            }
          ]
        },
        "formDescription": "Upload your photos and we'll categorise them for you!"
      },
      "typeVersion": 2.2
    },
    {
      "id": "e55afc94-d938-4028-acd5-05a794f3f601",
      "name": "Files to Items",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        -1152,
        272
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "$binary"
      },
      "typeVersion": 1
    },
    {
      "id": "1e42e96a-006d-442e-b449-44301c0e59ae",
      "name": "Get File Meta",
      "type": "n8n-nodes-base.set",
      "position": [
        -784,
        16
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={{ $binary[$binary.keys()[0]] }}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "2722b276-5737-48c5-88a6-e2da65d23a6c",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        -208,
        0
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "9fd14e8d-dad2-49ff-a68f-3b0a5099b196",
      "name": "Classify Photo and Suggest Tags",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        128,
        0
      ],
      "parameters": {
        "url": "https://api.featherless.ai/v1/chat/completions",
        "method": "POST",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 3000
            }
          }
        },
        "jsonBody": "={\n  \"model\": \"google/gemma-3-27b-it\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": [\n        {\n          \"type\": \"image_url\",\n          \"image_url\": {\n              \"url\": \"data:{{ $json.mimeType }};base64,{{ $json.data }}\"\n          }\n        },\n        {\n          \"type\": \"text\",\n          \"text\": \"Classify the image into one or more of following categories:Group Shot,Candid,Smiles,Food & Drink,Decorations,Fun,Laughter,Music,Dance Floor,Conversations,Networking,Toasting,Activity,Portrait,Venue,Best Dressed,Selfie,Cheers,Memories. If none of these categories apply, return \\\"Uncategorised\\\". Output your response as a comma-limited list only. Do not explain your reasoning.\"\n        }\n      ]\n    }\n  ]\n}\n",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "featherlessApi"
      },
      "credentials": {
        "featherlessApi": {
          "name": "<your credential>"
        },
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "80613233-6890-4bdb-9139-07270b3915e0",
      "name": "Extract Categories",
      "type": "n8n-nodes-base.set",
      "position": [
        352,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "de57f51d-ea18-4dd6-9bfa-53a1ff6c6b9b",
              "name": "categories",
              "type": "array",
              "value": "={{ $json.choices[0].message.content.split(',') }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "b5dd9fba-1d92-4bec-b2cb-8689961661c2",
      "name": "Upload file",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -784,
        432
      ],
      "parameters": {
        "name": "={{\n[\n  $('On form submission').item.json.Name,\n  '_',  \n  $execution.id,\n  '_',\n  $itemIndex,\n  '.',\n  $binary[$binary.keys()[0]].fileName.split('.')[1]\n].join('')\n}}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "1flK9aO20jw8Npf1EioiOl42i6FFLBGrX",
          "cachedResultUrl": "https://drive.google.com/drive/folders/1flK9aO20jw8Npf1EioiOl42i6FFLBGrX",
          "cachedResultName": "99. Event Photos"
        },
        "inputDataFieldName": "=Files_{{ $itemIndex }}"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "fc733296-dd2e-4f7f-9c05-9cc260dd52b9",
      "name": "Resize Image",
      "type": "n8n-nodes-base.editImage",
      "position": [
        -592,
        -144
      ],
      "parameters": {
        "width": "={{ $json.size.width > 512 ? 512 : $json.size.width }}",
        "height": "={{\n$json.size.width > 512\n  ? (512/$json.size.width) * $json.size.height\n  : $json.size.height\n}}",
        "options": {},
        "operation": "resize",
        "dataPropertyName": "=Files_{{ $itemIndex }}"
      },
      "typeVersion": 1
    },
    {
      "id": "c2a98a3c-6d2d-4aef-a39d-bd2e521a4919",
      "name": "Get Image Info",
      "type": "n8n-nodes-base.editImage",
      "position": [
        -784,
        -144
      ],
      "parameters": {
        "operation": "information",
        "dataPropertyName": "=Files_{{ $itemIndex }}"
      },
      "typeVersion": 1
    },
    {
      "id": "85049464-17cc-4bf9-bc08-004da7f5fe47",
      "name": "Merge1",
      "type": "n8n-nodes-base.merge",
      "position": [
        560,
        384
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "0be8ae30-b51d-4f86-b812-e060beb51e49",
      "name": "Create Payload",
      "type": "n8n-nodes-base.set",
      "position": [
        896,
        384
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "38b5af46-6664-4c58-95cd-8ab39128f1ec",
              "name": "url",
              "type": "string",
              "value": "={{ $json.webViewLink }}"
            },
            {
              "id": "71ef18c6-8df5-41a2-ab62-94c1683aeb9c",
              "name": "catergories",
              "type": "array",
              "value": "={{ $json.categories }}"
            },
            {
              "id": "f2a87d60-864a-4523-9672-582a14c1f8a5",
              "name": "submittedBy",
              "type": "string",
              "value": "={{ $('On form submission').first().json.Name }}"
            },
            {
              "id": "e0b36d69-ed3b-4b3a-99ca-b9d1a524bec1",
              "name": "submittedAt",
              "type": "string",
              "value": "={{ $('On form submission').item.json.submittedAt.toDateTime().toISO() }}"
            },
            {
              "id": "47fc9a70-427c-4bf5-b6ad-ee9bc18d8ebf",
              "name": "filename",
              "type": "string",
              "value": "={{ $json.name }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "6cb09d90-8699-4399-afde-84585a52c567",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1520,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 400,
        "content": "## 1. Allow Guests to Upload via Form Trigger\n[Learn more about the form trigger](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.formtrigger)\n\nThe form trigger is a quick and easy way to start getting data entry into a n8n workflow. Our form will allow our event guests to upload any number of photos under their own name. This form also works well on mobile which is super convenient!"
      },
      "typeVersion": 1
    },
    {
      "id": "ad6b5546-9ded-472c-8e88-df7ecf221f3b",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -880,
        -336
      ],
      "parameters": {
        "color": 7,
        "width": 816,
        "height": 560,
        "content": "## 2. Resize the Images for Faster Processing\n[Learn more about the Edit Image node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.editimage)\n\nIt's good practice to ensure we're optimising the input image as much as we can. Though with Featherless we may be less concerned about token cost, we still want to optimise for LLM processing speed which is affected by image size. Faster runs also frees up concurrency so we can handle more requests."
      },
      "typeVersion": 1
    },
    {
      "id": "53a1296e-b94b-44ff-8568-2f919f0b7b24",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -32,
        -336
      ],
      "parameters": {
        "color": 7,
        "width": 752,
        "height": 560,
        "content": "## 3. Categorise Photos using Gemma Model via [Featherless.ai](https://featherless.ai/register?referrer=HJUUTA6M)\n[Learn more about the Edit Image node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.editimage)\n\nMultimodal LLMs have proven to be incredibly powerful tools when working with images and trying to make sense of them. For this demonstration, we use Gemma - Google's small but capable multimodal model - to classify and categorise our guest photos and assign them a selection of preset tags.\n\n[Featherless.ai](https://featherless.ai/register?referrer=HJUUTA6M) is a popular inference provider which is fast becoming a favourite for teams who want predictable prices. Their pricing model is subscription based (starting from $10) but come with unlimited tokens which is prefect for a workflow such as this.\n\nFeatherless also hosts a range of other Gemma and Mistral models so definitely do check those out!"
      },
      "typeVersion": 1
    },
    {
      "id": "f0d1222d-13b0-4fd6-8b7b-4339e4ce2b01",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        752,
        128
      ],
      "parameters": {
        "color": 7,
        "width": 592,
        "height": 464,
        "content": "## 5. Save Entry Into Google Sheets Table \n[Learn more about the Google Sheet node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.googlesheets/)\n\nFinally, each photo along with the generated categories can be entered into a Google Sheets table which allows for filtering and sorting. Incredibly useful for later sharing to socials. Here's the sample sheet: https://docs.google.com/spreadsheets/d/1TpXQyhUq6tB8MLJ3maeWwswjut9wERZ8pSk_3kKhc58/edit?usp=sharing"
      },
      "typeVersion": 1
    },
    {
      "id": "d2cd8053-9714-4a17-bfaa-b1b2b602503f",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -880,
        256
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 352,
        "content": "## 4. Store a Copy of the Photo in Google Drive\n[Learn more about the Edit Image node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.editimage)\n\nFor this demonstration, we'll use Google Drive as our photo storage but feel free to swap this out for other storage options."
      },
      "typeVersion": 1
    },
    {
      "id": "b21787e6-8c35-443e-87f0-12fbda2e1573",
      "name": "Convert Image to Base64",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        -400,
        -144
      ],
      "parameters": {
        "options": {},
        "operation": "binaryToPropery",
        "binaryPropertyName": "=Files_{{ $itemIndex }}"
      },
      "typeVersion": 1
    },
    {
      "id": "508ff7a7-6609-4e0b-9d90-f6cb5a01f6b1",
      "name": "Append to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1088,
        384
      ],
      "parameters": {
        "columns": {
          "value": {
            "url": "={{ $json.url }}",
            "filename": "={{ $json.filename }}",
            "categories": "={{ $json.catergories.map(x => x.trim()).join(',') }}",
            "submittedAt": "={{ $json.submittedAt }}",
            "submittedBy": "={{ $json.submittedBy }}"
          },
          "schema": [
            {
              "id": "filename",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "filename",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "url",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "categories",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "categories",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "submittedBy",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "submittedBy",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "submittedAt",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "submittedAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1533965902,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1TpXQyhUq6tB8MLJ3maeWwswjut9wERZ8pSk_3kKhc58/edit#gid=1533965902",
          "cachedResultName": "Sheet2"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1TpXQyhUq6tB8MLJ3maeWwswjut9wERZ8pSk_3kKhc58",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1TpXQyhUq6tB8MLJ3maeWwswjut9wERZ8pSk_3kKhc58/edit?usp=drivesdk",
          "cachedResultName": "Event Photos"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "e7fea141-1b64-4002-99ec-72664effa41b",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2032,
        -608
      ],
      "parameters": {
        "width": 432,
        "height": 1456,
        "content": "## Classify User-Uploaded Photos for Public Events using [Featherless.ai](https://featherless.ai/register?referrer=HJUUTA6M)\n\n### During or after in-person events, trying to collect and share attendee photos has also been difficult and even when a collection forms, it becomes time-consuming to categorise and label.\n\nn8n can indeed help to solve this challenge by providing the data input interface via its forms and orchestrate AI-powered classification of images using AI nodes. However, in some cases - say you run regular events or with high attendee counts - the volume of photos may result in unsustainably high inference fees (token usage based billing) which could make the project unviable.\n\nTo work around this, [Featherless.ai](https://featherless.ai/register?referrer=HJUUTA6M) is an AI/LLM inference service which is subscription-based and provides unlimited tokens instead. This means costs are essentially capped for AI usage offering greater control and confidence on AI project budgets.\n\n**Check out the final result here:** [https://docs.google.com/spreadsheets/d/1TpXQyhUq6tB8MLJ3maeWwswjut9wERZ8pSk_3kKhc58/edit?usp=sharing](https://docs.google.com/spreadsheets/d/1TpXQyhUq6tB8MLJ3maeWwswjut9wERZ8pSk_3kKhc58/edit?usp=sharing)\n\n### How it works\n* A form trigger is used share a form interface to guests to upload their photos from their device.\n* The photos are in one branch, are optimised in size before sending to a vision-capable LLM to classify and categorise against a set list of tags. The model inference service is provided by Featherless and takes advantage of their unlimited token usage subscription plan.\n* The photos in another branch are copied into Google Drive for later reference.\n* Once both branches are complete, the classification results and Google Drive link are appended to a Google Sheets table allowing for quick sorting and filtering of all photos.\n\n### How to use\n* Use this workflow to gain an incredible productivity boost for social media work. When all photos are organised and filter-ready, editors spend a fraction of the time to get community posts ready and delivered.\n* Sharing the completed Google sheet with attendees helps them to better share memories within their own social circles.\n\n### Requirements\n* [FeatherLess.ai]((https://featherless.ai/register?referrer=HJUUTA6M)) account for Open Source Multimodal LLMs and unlimited token usage.\n* Google Drive for file storage\n* Google Sheet for organising photos into categories\n\n### Customising this workflow\n* Feel free to refine the form with custom styles to match your branding.\n* Swap out Google services with equivalents to match your own environment. eg. Sharepoint and Excel.\n\n### Need Help?\nJoin the [Discord](https://discord.com/invite/XPKeKXeB7d) or ask in the [Forum](https://community.n8n.io/)!\n\nHappy Hacking!"
      },
      "typeVersion": 1
    },
    {
      "id": "2de76e89-2695-47f7-9b1d-320cac100515",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2032,
        880
      ],
      "parameters": {
        "width": 432,
        "height": 256,
        "content": "![](https://cdn.subworkflow.ai/n8n-templates/banner_595x311.png#full-width)"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Merge": {
      "main": [
        [
          {
            "node": "Classify Photo and Suggest Tags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge1": {
      "main": [
        [
          {
            "node": "Create Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload file": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Resize Image": {
      "main": [
        [
          {
            "node": "Convert Image to Base64",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get File Meta": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Create Payload": {
      "main": [
        [
          {
            "node": "Append to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Files to Items": {
      "main": [
        [
          {
            "node": "Get File Meta",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Image Info",
            "type": "main",
            "index": 0
          },
          {
            "node": "Upload file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Image Info": {
      "main": [
        [
          {
            "node": "Resize Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Categories": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "Files to Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert Image to Base64": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Classify Photo and Suggest Tags": {
      "main": [
        [
          {
            "node": "Extract Categories",
            "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

n8n can indeed help to solve this challenge by providing the data input interface via its forms and orchestrate AI-powered classification of images using AI nodes. However, in some cases - say you run regular events or with high attendee counts - the volume of photos may result…

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

📄 Documentation: Notion Guide

Google Sheets, Google Drive, HTTP Request +2
Data & Sheets

Description: The Spotify Music Downloader is an automation flow that allows users to easily download music from Spotify tracks. By leveraging the powerful Spotify Downloader API, the flow downloads Sp

Form Trigger, HTTP Request, Google Drive +1
Data & Sheets

Automate downloading Threads videos from URLs, upload them to Google Drive, and log results in Google Sheets using n8n.

Form Trigger, HTTP Request, Google Drive +1
Data & Sheets

Description: This n8n workflow automates the process of downloading videos from any supported platform (like LinkedIn, Facebook, or Instagram) using the RapidAPI best All-In-One Video Downloader. It t

Form Trigger, HTTP Request, Google Drive +1
Data & Sheets

📝 On Form Submission → Displays a form for users to input the Slideshare URL. 🌐 Slideshare Downloader → Sends the submitted URL to the Slideshare Downloader Pro API to fetch a downloadable PDF link. ✅

Form Trigger, Google Drive, Google Sheets +1