This workflow corresponds to n8n.io template #4274 — we link there as the canonical source.
This workflow follows the HTTP Request → OpenAI 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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "b2a1a367-119f-4e2d-a982-ff675debf658",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
220,
-40
],
"parameters": {
"color": 7,
"width": 180,
"height": 260,
"content": "Check how far apart the actual code is from the expected code (a score of 1 is a perfect match)"
},
"typeVersion": 1
},
{
"id": "f5413855-20de-4b77-ba90-18610a9d9b4d",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1300,
40
],
"parameters": {
"width": 300,
"height": 500,
"content": "## How it works\nThis template shows how to calculate a workflow evaluation metric: **text similarity, measured character-by-character**.\n\nThe workflow takes images of hand-written codes, extracts the code and compares it with the expected answer from the dataset.\n\nThe images look like this:\n\n\nYou can find more information on workflow evaluation [here](https://docs.n8n.io/advanced-ai/evaluations/overview), and other metric examples [here](https://docs.n8n.io/advanced-ai/evaluations/metric-based-evaluations/#2-calculate-metrics)."
},
"typeVersion": 1
},
{
"id": "8921a4c4-cee1-44e7-8dce-55219db519d7",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-960,
280
],
"parameters": {
"color": 7,
"width": 220,
"height": 220,
"content": "Read in [this test dataset](https://docs.google.com/spreadsheets/d/1uuPS5cHtSNZ6HNLOi75A2m8nVWZrdBZ_Ivf58osDAS8/edit?gid=1786963566#gid=1786963566) of images"
},
"typeVersion": 1
},
{
"id": "fbf8337b-eb46-443a-8507-58a14b817be0",
"name": "Match webhook format",
"type": "n8n-nodes-base.set",
"position": [
-680,
340
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "= {\n \"headers\": {\n },\n \"params\": {},\n \"query\": {\n \"url\": {{ $json.file_url.toJsonString() }}\n },\n \"body\": {},\n \"executionMode\": \"test\"\n }"
},
"typeVersion": 3.4
},
{
"id": "a03c9b79-d45d-4842-9325-df1af37697eb",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-900,
40
],
"parameters": {
"path": "7ceb775c-b961-44f0-acfe-682a67612332",
"options": {}
},
"typeVersion": 2
},
{
"id": "85bd63e2-3039-4f0e-8721-bc2b843461c9",
"name": "When fetching a dataset row",
"type": "n8n-nodes-base.evaluationTrigger",
"position": [
-900,
340
],
"parameters": {
"sheetName": {
"__rl": true,
"mode": "url",
"value": "https://docs.google.com/spreadsheets/d/1uuPS5cHtSNZ6HNLOi75A2m8nVWZrdBZ_Ivf58osDAS8/edit?gid=1786963566#gid=1786963566"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "https://docs.google.com/spreadsheets/d/1uuPS5cHtSNZ6HNLOi75A2m8nVWZrdBZ_Ivf58osDAS8/edit?gid=1786963566#gid=1786963566"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "4ed0b460-70af-4f1d-a7f3-97293f9b4ce0",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
260,
320
],
"parameters": {
"options": {}
},
"typeVersion": 1.3
},
{
"id": "f1642aa1-94c5-4002-a7aa-533566dd20eb",
"name": "Evaluating?",
"type": "n8n-nodes-base.evaluation",
"position": [
-20,
200
],
"parameters": {
"operation": "checkIfEvaluating"
},
"typeVersion": 4.6
},
{
"id": "15115588-b9ca-4e24-b7d8-f0aa0974b5dd",
"name": "Set metrics",
"type": "n8n-nodes-base.evaluation",
"position": [
480,
80
],
"parameters": {
"metrics": {
"assignments": [
{
"id": "0e507b06-e6d5-4ace-aa22-f06c6db5b883",
"name": "score",
"type": "number",
"value": "={{ $json.score }}"
}
]
},
"operation": "setMetrics"
},
"typeVersion": 4.6
},
{
"id": "af028132-c866-487d-be85-e3af049bc793",
"name": "Extract code from image",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
-240,
200
],
"parameters": {
"text": "=Extract ONLY the handwritten code in the top-right corner of this image.\n\nThe code MUST follow this EXACT format:\nBT/ED/[1-3 capital letters]/[1-3 capital letters]/[1-3 capital letters]/[1-3 capital letters or empty]/[single letter + number (2-4 chars total)]\n\nExamples of correct format:\nBT/ED/ABC/DE/F/G/H1\nBT/ED/A/BC/DEF/GH/I23\nBT/ED/AB/CD/EF/GH/I234\n\nDO NOT include any explanations, notes, or other text.\nDO NOT return anything if the code doesn't match the required format.\nVERIFY the extracted code matches the format before returning it.\nReturn ONLY the extracted code - nothing else.",
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o",
"cachedResultName": "GPT-4O"
},
"options": {},
"resource": "image",
"inputType": "base64",
"operation": "analyze"
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.8
},
{
"id": "50a26635-078f-40a7-8944-2e43ed8cd482",
"name": "Calc string distance",
"type": "n8n-nodes-base.code",
"position": [
260,
80
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const expected_code = $('When fetching a dataset row').item.json.expected_output\nconst actual_code = $json.content\n\nfunction levenshteinDistance(str1, str2) {\n const m = str1.length;\n const n = str2.length;\n const dp = Array(m + 1).fill().map(() => Array(n + 1).fill(0));\n\n for (let i = 0; i <= m; i++) {\n dp[i][0] = i;\n }\n \n for (let j = 0; j <= n; j++) {\n dp[0][j] = j;\n }\n\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n if (str1[i - 1] === str2[j - 1]) {\n dp[i][j] = dp[i - 1][j - 1];\n } else {\n dp[i][j] = 1 + Math.min(\n dp[i - 1][j], // deletion\n dp[i][j - 1], // insertion\n dp[i - 1][j - 1] // substitution\n );\n }\n }\n }\n\n return dp[m][n];\n}\n\nconst dist = levenshteinDistance(\n expected_code, \n actual_code\n)\n\nconst max_dist = Math.max(\n expected_code.length,\n actual_code.length\n)\n\nconsole.log('truth', expected_code)\nconsole.log('effort', actual_code)\nconsole.log('dist', dist)\nconsole.log('max_dist', max_dist)\n\n$input.item.json.score = 1 - (dist / max_dist)\n\nreturn $input.item;"
},
"typeVersion": 2
},
{
"id": "383db4b0-9665-4608-bbf9-3dca88508bff",
"name": "Download image",
"type": "n8n-nodes-base.httpRequest",
"position": [
-460,
200
],
"parameters": {
"url": "={{ $json.query.url }}",
"options": {}
},
"typeVersion": 4.2
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Download image",
"type": "main",
"index": 0
}
]
]
},
"Evaluating?": {
"main": [
[
{
"node": "Calc string distance",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Download image": {
"main": [
[
{
"node": "Extract code from image",
"type": "main",
"index": 0
}
]
]
},
"Calc string distance": {
"main": [
[
{
"node": "Set metrics",
"type": "main",
"index": 0
}
]
]
},
"Match webhook format": {
"main": [
[
{
"node": "Download image",
"type": "main",
"index": 0
}
]
]
},
"Extract code from image": {
"main": [
[
{
"node": "Evaluating?",
"type": "main",
"index": 0
}
]
]
},
"When fetching a dataset row": {
"main": [
[
{
"node": "Match webhook format",
"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.
googleSheetsOAuth2ApiopenAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This is a template for n8n's evaluation feature.
Source: https://n8n.io/workflows/4274/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This powerful n8n automation workflow is designed to execute advanced B2B lead enrichment and hyper-personalization for cold email outreach. By orchestrating a complex chain of data scraping, AI analy
This workflow bridges the gap between raw product data and revenue sales tools. It automates the entire Product Qualified Lead (PQL) lifecycle—from real-time intent routing to churn prevention—reducin
User Signup & Verification: The workflow starts when a user signs up. It generates a verification code and sends it via SMS using Twilio. Code Validation: The user replies with the code. The workflow
Generates a wordlist of 1,000–15,000 subdomains created by an AI agent by correlating detected technologies and recurring patterns.
This template is perfect for e-commerce entrepreneurs, marketers, agencies, and creative teams who want to turn simple product photos and short descriptions into professional flyers or product videos—