This workflow corresponds to n8n.io template #17452 — we link there as the canonical source.
This workflow follows the Chainllm → Form Trigger 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 →
{
"id": "PouvVM4cHKNXSgum",
"name": "Contract & ToS Red-Flag Analyzer (AI, Plain-English Risk Report)",
"tags": [],
"nodes": [
{
"id": "a9d8860e-f8fe-441c-b1d9-58dae2d1f2d5",
"name": "Sticky Note - Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-32,
0
],
"parameters": {
"width": 460,
"height": 1060,
"content": "Most people sign contracts and terms of service without reading every clause, and problems only surface once it is too late to negotiate. This workflow reads any pasted contract, lease, NDA, or terms of service and returns a plain English risk report in under a minute. It is built for freelancers, renters, employees, and small business owners who want to know what they are agreeing to before they sign. The output is not legal advice, it is a starting point for asking better questions.\n\n### How it works\n1. The Form Trigger collects the contract text, the person's role, and an optional document type.\n2. Map Form Fields cleans the submitted data into simple fields.\n3. Long Enough? checks there is enough text to analyze, short submissions get a friendly error instead of wasting a request.\n4. Prepare Input trims very long contracts so they stay inside the AI model's limits.\n5. Analyze Contract sends the text to the AI model, which returns a risk score, summary, and flagged clauses.\n6. Build HTML Report formats that data into a report, and Send Report shows it back to the user right away.\n\n### Setup steps\n1. Open the OpenAI Chat Model node (node 7) and connect your own OpenAI credential. Any Chat Model node works the same way for Anthropic or Gemini.\n2. No other credentials or placeholders are needed.\n3. Activate the workflow, then open the Form Trigger's production URL and test it with a real contract.\n\n### Customization\nAdjust the 200 character minimum in Long Enough? for stricter or looser validation. Change the risk categories or the prompt in Analyze Contract to match a specific industry."
},
"typeVersion": 1
},
{
"id": "c2fc3263-93ee-4b96-844c-7d89bdae46b9",
"name": "Sticky Note - Section 1",
"type": "n8n-nodes-base.stickyNote",
"position": [
480,
144
],
"parameters": {
"color": 7,
"width": 972,
"height": 580,
"content": "## 1. Collect and validate input\nGrabs the contract text and role from the form, checks there is enough text to analyze, and trims anything too long before it reaches the AI."
},
"typeVersion": 1
},
{
"id": "05c4847c-3ccc-4f8b-8bbc-3832bd8455b6",
"name": "Sticky Note - Section 2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1504,
48
],
"parameters": {
"color": 7,
"width": 417,
"height": 742,
"content": "## 2. Analyze contract with AI\nThe AI model reads the text and returns a structured risk score, a summary, and a list of clauses that could work against the user."
},
"typeVersion": 1
},
{
"id": "14637237-4eb8-4be5-90ac-15187bff90e9",
"name": "Sticky Note - Section 3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1936,
144
],
"parameters": {
"color": 7,
"width": 487,
"height": 374,
"content": "## 3. Build and deliver the report\nTurns the AI's output into a color coded HTML report and shows it back to whoever submitted the form."
},
"typeVersion": 1
},
{
"id": "edc9350a-5b97-49d2-bd4e-2117d6c0b9fc",
"name": "Form Trigger",
"type": "n8n-nodes-base.formTrigger",
"position": [
544,
384
],
"parameters": {
"options": {
"buttonLabel": "Analyze My Contract",
"appendAttribution": false
},
"formTitle": "Contract & ToS Red-Flag Analyzer",
"formFields": {
"values": [
{
"fieldType": "textarea",
"fieldLabel": "Paste the contract or terms of service text",
"requiredField": true
},
{
"fieldType": "dropdown",
"fieldLabel": "Your role in this agreement",
"fieldOptions": {
"values": [
{
"option": "Tenant / Renter"
},
{
"option": "Freelancer / Contractor"
},
{
"option": "Employee"
},
{
"option": "Business / Vendor"
},
{
"option": "Consumer / App or Service User"
},
{
"option": "Other"
}
]
},
"requiredField": true
},
{
"fieldType": "dropdown",
"fieldLabel": "Document type (optional, helps accuracy)",
"fieldOptions": {
"values": [
{
"option": "Not sure / Skip"
},
{
"option": "Rental Lease"
},
{
"option": "Freelance / Service Contract"
},
{
"option": "SaaS Terms of Service"
},
{
"option": "NDA"
},
{
"option": "Employment Agreement"
},
{
"option": "Vendor / Partnership Agreement"
}
]
}
}
]
},
"formDescription": "Paste any contract, terms of service, NDA, lease, or agreement below. Get a plain-English breakdown of risky clauses in under a minute. This is not legal advice. Always consult a qualified lawyer for decisions that matter."
},
"typeVersion": 2.2
},
{
"id": "e8b9dfbc-d4fe-4575-a68a-0e1b71e4b9bf",
"name": "Map Form Fields",
"type": "n8n-nodes-base.code",
"position": [
784,
384
],
"parameters": {
"jsCode": "const item = $input.first().json;\n\nreturn [{\n json: {\n contractText: (item['Paste the contract or terms of service text'] || '').trim(),\n role: item['Your role in this agreement'] || 'Other',\n docType: item['Document type (optional, helps accuracy)'] || 'Not sure / Skip'\n }\n}];"
},
"typeVersion": 2
},
{
"id": "e66ca10a-2237-4b4b-8377-81dc319c9b89",
"name": "Long Enough?",
"type": "n8n-nodes-base.if",
"position": [
1008,
384
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "cond1",
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.contractText.length }}",
"rightValue": 200
}
]
}
},
"typeVersion": 2.2
},
{
"id": "0aab55fc-400f-49f2-a052-e1be84d2363c",
"name": "Too Short - Error Response",
"type": "n8n-nodes-base.form",
"position": [
1248,
544
],
"parameters": {
"operation": "completion",
"respondWith": "showText",
"responseText": "<html><body style=\"font-family:-apple-system,Segoe UI,Roboto,sans-serif;padding:60px;text-align:center;color:#111827;\"><h2>Please paste more text</h2><p style=\"color:#6b7280;\">Add at least a full paragraph of the contract or terms of service (about 200+ characters) so the analysis is accurate. Go back and try again.</p></body></html>"
},
"typeVersion": 1
},
{
"id": "5e64f6ed-5aa7-4204-8ba4-b4b199aa8138",
"name": "Prepare Input",
"type": "n8n-nodes-base.code",
"position": [
1248,
288
],
"parameters": {
"jsCode": "const item = $input.first().json;\nlet text = item.contractText;\nlet truncated = false;\n\nif (text.length > 14000) {\n text = text.slice(0, 14000);\n truncated = true;\n}\n\nreturn [{\n json: {\n contractText: text,\n role: item.role,\n docType: item.docType,\n truncated\n }\n}];"
},
"typeVersion": 2
},
{
"id": "b217a567-5f52-4187-b007-e60e986f04c5",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1552,
512
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-mini"
},
"options": {
"temperature": 0.2
}
},
"typeVersion": 1.2
},
{
"id": "7c9b705d-d203-4495-93b2-0de0f03acd37",
"name": "Risk Report Schema",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
1712,
512
],
"parameters": {
"jsonSchemaExample": "{\n \"overall_risk\": 7,\n \"risk_reason\": \"Contains an automatic renewal clause and a broad liability waiver.\",\n \"summary\": \"This agreement renews automatically each year and limits the company's liability to the amount you paid.\",\n \"flags\": [\n {\n \"clause\": \"This Agreement will automatically renew for successive one-year terms unless either party provides 60 days written notice.\",\n \"category\": \"Auto-Renewal\",\n \"risk_level\": \"High\",\n \"explanation\": \"You could be locked in for another full year if you forget to cancel in time.\",\n \"suggested_action\": \"Ask if the notice period can be shortened to 30 days, or set a calendar reminder well before the deadline.\"\n }\n ]\n}"
},
"typeVersion": 1.3
},
{
"id": "d7c64b19-1ee5-413e-b8e5-b02cbf0f7d0e",
"name": "Analyze Contract",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
1552,
288
],
"parameters": {
"text": "=You are a contract-review assistant who explains agreements in plain, everyday English for people who are not lawyers.\n\nThe person reviewing this identifies as: {{ $json.role }}\nDocument type: {{ $json.docType }}\n\nAnalyze the CONTRACT TEXT below and respond with:\n1. overall_risk: a number from 1-10 (10 = extremely risky for this person)\n2. risk_reason: one sentence explaining the overall_risk score\n3. summary: 2-3 plain-English sentences on what this agreement generally requires from this person\n4. flags: an array of every clause that could meaningfully disadvantage this person. For each one include:\n - clause: the relevant text quoted or closely paraphrased from the contract (keep it short)\n - category: one of Auto-Renewal, Liability, Termination, Fees & Penalties, Data & Privacy, Non-Compete, Dispute Resolution, IP Ownership, Other\n - risk_level: Critical, High, Medium, or Low\n - explanation: plain-English reason this matters, written for a non-lawyer\n - suggested_action: a question to ask or point to negotiate, not legal advice\n\nRules:\n- Never invent a clause that is not in the text.\n- If there is nothing notably risky, say so in the summary and return an empty flags array.\n- Never state what the person should legally do. Only explain risk and suggest questions to raise with a professional.\n\nCONTRACT TEXT:\n{{ $json.contractText }}",
"batching": {},
"messages": {
"messageValues": []
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.7
},
{
"id": "a07c3fee-3489-40fa-8cfc-91ba7edf183f",
"name": "Build HTML Report",
"type": "n8n-nodes-base.code",
"position": [
1984,
288
],
"parameters": {
"jsCode": "const data = $input.first().json.output;\n\nconst riskColor = (level) => {\n const map = { Critical: '#dc2626', High: '#ea580c', Medium: '#ca8a04', Low: '#16a34a' };\n return map[level] || '#6b7280';\n};\n\nconst scoreColor = data.overall_risk >= 8 ? '#dc2626' : data.overall_risk >= 5 ? '#ea580c' : data.overall_risk >= 3 ? '#ca8a04' : '#16a34a';\n\nconst flagsHtml = (data.flags || []).map(f => `\n <div style=\"border:1px solid #e5e7eb;border-left:4px solid ${riskColor(f.risk_level)};border-radius:8px;padding:16px;margin-bottom:14px;background:#fff;\">\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <span style=\"font-weight:600;color:#111827;\">${f.category}</span>\n <span style=\"background:${riskColor(f.risk_level)};color:#fff;font-size:12px;font-weight:600;padding:3px 10px;border-radius:999px;\">${f.risk_level}</span>\n </div>\n <p style=\"color:#4b5563;font-style:italic;margin:6px 0;font-size:14px;\">\"${f.clause}\"</p>\n <p style=\"color:#111827;margin:6px 0;font-size:14px;\"><strong>Why it matters:</strong> ${f.explanation}</p>\n <p style=\"color:#111827;margin:6px 0;font-size:14px;\"><strong>What to do:</strong> ${f.suggested_action}</p>\n </div>\n`).join('');\n\nconst noFlagsHtml = `<p style=\"color:#16a34a;font-weight:600;\">No notably risky clauses were found in the text provided.</p>`;\n\nconst html = `\n<!DOCTYPE html>\n<html>\n<head><meta charset=\"utf-8\"><title>Contract Risk Report</title></head>\n<body style=\"font-family:-apple-system,Segoe UI,Roboto,sans-serif;background:#f9fafb;margin:0;padding:32px;\">\n <div style=\"max-width:680px;margin:0 auto;\">\n <h1 style=\"color:#111827;font-size:22px;margin-bottom:4px;\">Contract Risk Report</h1>\n <p style=\"color:#6b7280;font-size:13px;margin-top:0;\">AI-generated. Not legal advice, for decisions that matter consult a qualified lawyer.</p>\n\n <div style=\"background:#fff;border:1px solid #e5e7eb;border-radius:10px;padding:20px;margin:20px 0;display:flex;align-items:center;gap:20px;\">\n <div style=\"font-size:36px;font-weight:700;color:${scoreColor};\">${data.overall_risk}/10</div>\n <div>\n <div style=\"font-weight:600;color:#111827;\">Overall Risk</div>\n <div style=\"color:#4b5563;font-size:14px;\">${data.risk_reason}</div>\n </div>\n </div>\n\n <div style=\"background:#fff;border:1px solid #e5e7eb;border-radius:10px;padding:20px;margin:20px 0;\">\n <div style=\"font-weight:600;color:#111827;margin-bottom:6px;\">Summary</div>\n <p style=\"color:#4b5563;font-size:14px;margin:0;\">${data.summary}</p>\n </div>\n\n <h2 style=\"color:#111827;font-size:17px;\">Flagged Clauses (${(data.flags||[]).length})</h2>\n ${(data.flags && data.flags.length) ? flagsHtml : noFlagsHtml}\n\n <p style=\"color:#9ca3af;font-size:12px;margin-top:30px;\">Generated by an AI contract analyzer. This report explains risk in plain English; it does not constitute legal advice or an attorney-client relationship.</p>\n </div>\n</body>\n</html>`;\n\nreturn [{ json: { html } }];"
},
"typeVersion": 2
},
{
"id": "b83c4540-c04a-4cbd-99b8-021fbbd9adab",
"name": "Send Report",
"type": "n8n-nodes-base.form",
"position": [
2208,
288
],
"parameters": {
"operation": "completion",
"respondWith": "showText",
"responseText": "={{ $json.html }}"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "10174823-dff6-4417-8866-4d141852f139",
"nodeGroups": [],
"connections": {
"Form Trigger": {
"main": [
[
{
"node": "Map Form Fields",
"type": "main",
"index": 0
}
]
]
},
"Long Enough?": {
"main": [
[
{
"node": "Prepare Input",
"type": "main",
"index": 0
}
],
[
{
"node": "Too Short - Error Response",
"type": "main",
"index": 0
}
]
]
},
"Prepare Input": {
"main": [
[
{
"node": "Analyze Contract",
"type": "main",
"index": 0
}
]
]
},
"Map Form Fields": {
"main": [
[
{
"node": "Long Enough?",
"type": "main",
"index": 0
}
]
]
},
"Analyze Contract": {
"main": [
[
{
"node": "Build HTML Report",
"type": "main",
"index": 0
}
]
]
},
"Build HTML Report": {
"main": [
[
{
"node": "Send Report",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Analyze Contract",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Risk Report Schema": {
"ai_outputParser": [
[
{
"node": "Analyze Contract",
"type": "ai_outputParser",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow collects pasted contract or terms-of-service text via an n8n Form and uses OpenAI to generate a structured risk score, plain-English summary, and flagged clauses, then returns a color-coded HTML report to the submitter. Receives a submission from an n8n Form…
Source: https://n8n.io/workflows/17452/ — 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.
Host Your Own AI Deep Research Agent with n8n, Apify and OpenAI. Uses outputParserStructured, lmChatOpenAi, formTrigger, chainLlm. Event-driven trigger; 87 nodes.
This template attempts to replicate OpenAI's DeepResearch feature which, at time of writing, is only available to their pro subscribers.
My workflow 53. Uses formTrigger, httpRequest, lmChatOpenAi, form. Event-driven trigger; 74 nodes.
This workflow serves as a comprehensive "Workflow Nodes SEO & Documentation Generator". It uses AI to analyze, rename, and document n8n workflows, offering a streamlined way to optimize workflow reada
This workflow streamlines how employees request equipment/items and how those requests reach the Procurement team. It validates the employee by enrollment number, detects whether a manager exists, and