AutomationFlowsEmail & Gmail › Explain Contract Pdfs and Flag Risky Clauses with Gemini and Gmail

Explain Contract Pdfs and Flag Risky Clauses with Gemini and Gmail

ByOka Hironobu @okp29 on n8n.io

This workflow collects a contract PDF via an n8n form, extracts its text, uses Google Gemini to generate a structured plain-language review with risk flags, logs the results to Google Sheets, and emails the requester a different summary based on the detected risk level. Receives…

Event trigger★★★★☆ complexityAI-powered20 nodesForm TriggerChain LlmGoogle Gemini ChatOutput Parser StructuredGoogle SheetsGmail
Email & Gmail Trigger: Event Nodes: 20 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #17413 — 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 →

Download .json
{
  "id": "p4J3f2FvJmmgum8I",
  "meta": {
    "builderVariant": "mcp",
    "aiBuilderAssisted": true
  },
  "name": "Explain any contract PDF in plain language with Gemini and flag risky clauses",
  "tags": [],
  "nodes": [
    {
      "id": "0dcadb7b-aa71-440d-a8b1-0a20012916e9",
      "name": "Contract Upload Form",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        48,
        48
      ],
      "parameters": {
        "options": {
          "buttonLabel": "Explain my contract",
          "respondWithOptions": {
            "values": {
              "formSubmittedText": "Thanks! Your plain-language summary will arrive by email shortly."
            }
          }
        },
        "formTitle": "Explain this contract to me",
        "formFields": {
          "values": [
            {
              "fieldType": "email",
              "fieldLabel": "Your email",
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Document type",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Rental or lease agreement"
                  },
                  {
                    "option": "Insurance policy"
                  },
                  {
                    "option": "Employment contract"
                  },
                  {
                    "option": "Terms of service"
                  },
                  {
                    "option": "Other"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "What worries you",
              "placeholder": "e.g. Can the landlord raise the rent mid-term?"
            },
            {
              "fieldType": "file",
              "fieldLabel": "Contract",
              "multipleFiles": false,
              "requiredField": true,
              "acceptFileTypes": ".pdf"
            }
          ]
        },
        "formDescription": "Upload a lease, insurance policy, employment contract or terms of service and get it explained in plain language with the risky parts flagged."
      },
      "typeVersion": 2.6
    },
    {
      "id": "4bce86a7-2f5c-4e47-8406-0856d34305df",
      "name": "Extract Contract Text",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        272,
        48
      ],
      "parameters": {
        "options": {},
        "operation": "pdf",
        "binaryPropertyName": "Contract"
      },
      "typeVersion": 1.1
    },
    {
      "id": "1e6e9405-39a5-4bb5-9bb9-5d8833ec3545",
      "name": "Has Readable Text",
      "type": "n8n-nodes-base.if",
      "position": [
        480,
        48
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ ($json.text || \"\").length }}",
              "rightValue": 300
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "f98fae34-1c47-4d19-8c29-de61b5437687",
      "name": "Explain Contract with Gemini",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "onError": "continueErrorOutput",
      "position": [
        928,
        32
      ],
      "parameters": {
        "text": "=You are a careful contract reviewer helping an ordinary person who is not a lawyer. Explain the {{ $('Contract Upload Form').item.json['Document type'] }} below in plain language with no legal jargon. Give a short plain summary, an overall risk_level of low, medium or high, the obligations this person is taking on, the key dates and notice periods, the costs and penalties, and any clauses that are unusual or one-sided with why they matter and a severity. Also list the questions they should ask before signing. If they raised a specific concern, answer it directly in answer_to_concern, quoting the relevant clause. Be accurate and never invent clauses that are not in the text.\n\nTheir concern: {{ $('Contract Upload Form').item.json['What worries you'] }}\n\nContract:\n{{ $json.text }}",
        "batching": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.9
    },
    {
      "id": "edd31b1a-a64b-4db4-99b6-be22b98bbbe6",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        912,
        192
      ],
      "parameters": {
        "options": {
          "temperature": 0.2,
          "maxOutputTokens": 4096
        },
        "modelName": "models/gemini-3.1-flash-lite"
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "ef743ce4-0bc6-45ef-ba3a-9c23ecc1e2bf",
      "name": "Contract Review Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1088,
        192
      ],
      "parameters": {
        "jsonSchemaExample": "{\"plain_summary\":\"You rent the flat for 12 months at 1200 a month\",\"risk_level\":\"medium\",\"your_obligations\":[\"Pay rent by the 1st\"],\"key_dates\":[\"Notice must be given 2 months before the end\"],\"costs\":[\"Deposit of 2400\"],\"risky_clauses\":[{\"clause\":\"Landlord may increase rent with 30 days notice\",\"why\":\"No cap on the increase\",\"severity\":\"high\"}],\"questions_to_ask\":[\"Is there a cap on rent increases?\"],\"answer_to_concern\":\"Yes, clause 8 allows a mid-term increase\"}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "2d2dcdd1-1407-42dc-ae10-87623fa44283",
      "name": "Parse Contract Review",
      "type": "n8n-nodes-base.code",
      "position": [
        1584,
        16
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const src = $json.output || $json;\nconst f = $('Contract Upload Form').item.json;\nconst list = function (x) { return Array.isArray(x) ? x : []; };\nconst bullets = function (x) { return list(x).map(function (i) { return '- ' + i; }).join('\\n'); };\nconst risky = list(src.risky_clauses).map(function (c) { return { clause: c.clause || '', why: c.why || '', severity: String(c.severity || 'medium').toLowerCase() }; });\nreturn {\n  email: f['Your email'] || '',\n  docType: f['Document type'] || '',\n  concern: f['What worries you'] || '',\n  plainSummary: src.plain_summary || '',\n  riskLevel: String(src.risk_level || 'medium').toLowerCase(),\n  obligations: bullets(src.your_obligations),\n  keyDates: bullets(src.key_dates),\n  costs: bullets(src.costs),\n  questions: bullets(src.questions_to_ask),\n  answerToConcern: src.answer_to_concern || '',\n  riskyCount: risky.length,\n  riskyText: risky.map(function (c) { return '- [' + c.severity.toUpperCase() + '] ' + c.clause + ' -> ' + c.why; }).join('\\n'),\n  riskyClauses: risky\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "ab800c31-19d1-4865-bdef-e820cbca80bf",
      "name": "Log Contract Review",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1824,
        16
      ],
      "parameters": {
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Contract Reviews"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select your spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "1aa0e448-5b25-4318-b9b7-40b410c8cfdb",
      "name": "Route by Risk Level",
      "type": "n8n-nodes-base.switch",
      "position": [
        2112,
        -16
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $(\"Parse Contract Review\").item.json.riskLevel }}",
                    "rightValue": "high"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $(\"Parse Contract Review\").item.json.riskLevel }}",
                    "rightValue": "medium"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $(\"Parse Contract Review\").item.json.riskLevel }}",
                    "rightValue": "low"
                  }
                ]
              }
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "Other"
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "fcc5e76c-3e6a-41eb-bd06-f99d957a6f22",
      "name": "Email Do Not Sign Yet",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2384,
        -32
      ],
      "parameters": {
        "sendTo": "={{ $(\"Parse Contract Review\").item.json.email }}",
        "message": "={{ \"In plain language:\\n\" + $(\"Parse Contract Review\").item.json.plainSummary + \"\\n\\nThis contract has clauses worth pushing back on:\\n\" + $(\"Parse Contract Review\").item.json.riskyText + \"\\n\\nAsk these before you sign:\\n\" + $(\"Parse Contract Review\").item.json.questions + \"\\n\\nYour obligations:\\n\" + $(\"Parse Contract Review\").item.json.obligations + \"\\n\\nKey dates:\\n\" + $(\"Parse Contract Review\").item.json.keyDates + \"\\n\\nCosts:\\n\" + $(\"Parse Contract Review\").item.json.costs + \"\\n\\nOn your question:\\n\" + $(\"Parse Contract Review\").item.json.answerToConcern + \"\\n\\nThis is an AI summary, not legal advice. For anything significant, have a qualified lawyer review it.\" }}",
        "options": {},
        "subject": "={{ \"Do not sign yet - \" + $(\"Parse Contract Review\").item.json.docType }}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "279592d8-b555-452c-9016-00b7a0888f3a",
      "name": "Email Review Before Signing",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2384,
        128
      ],
      "parameters": {
        "sendTo": "={{ $(\"Parse Contract Review\").item.json.email }}",
        "message": "={{ \"In plain language:\\n\" + $(\"Parse Contract Review\").item.json.plainSummary + \"\\n\\nClauses to check:\\n\" + $(\"Parse Contract Review\").item.json.riskyText + \"\\n\\nQuestions to ask:\\n\" + $(\"Parse Contract Review\").item.json.questions + \"\\n\\nYour obligations:\\n\" + $(\"Parse Contract Review\").item.json.obligations + \"\\n\\nKey dates:\\n\" + $(\"Parse Contract Review\").item.json.keyDates + \"\\n\\nCosts:\\n\" + $(\"Parse Contract Review\").item.json.costs + \"\\n\\nOn your question:\\n\" + $(\"Parse Contract Review\").item.json.answerToConcern + \"\\n\\nThis is an AI summary, not legal advice.\" }}",
        "options": {},
        "subject": "={{ \"Worth a closer look - \" + $(\"Parse Contract Review\").item.json.docType }}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "060d8a75-9fe0-4ce6-aa27-17ba13179ba5",
      "name": "Email Plain Summary",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2384,
        288
      ],
      "parameters": {
        "sendTo": "={{ $(\"Parse Contract Review\").item.json.email }}",
        "message": "={{ \"In plain language:\\n\" + $(\"Parse Contract Review\").item.json.plainSummary + \"\\n\\nNothing unusual stood out.\\n\\nYour obligations:\\n\" + $(\"Parse Contract Review\").item.json.obligations + \"\\n\\nKey dates:\\n\" + $(\"Parse Contract Review\").item.json.keyDates + \"\\n\\nCosts:\\n\" + $(\"Parse Contract Review\").item.json.costs + \"\\n\\nOn your question:\\n\" + $(\"Parse Contract Review\").item.json.answerToConcern + \"\\n\\nThis is an AI summary, not legal advice.\" }}",
        "options": {},
        "subject": "={{ \"Your \" + $(\"Parse Contract Review\").item.json.docType + \" explained\" }}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "58d6d58d-70e1-475d-a20d-a4b497075e8c",
      "name": "Email Generic Summary",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2384,
        448
      ],
      "parameters": {
        "sendTo": "={{ $(\"Parse Contract Review\").item.json.email }}",
        "message": "={{ $(\"Parse Contract Review\").item.json.plainSummary + \"\\n\\nObligations:\\n\" + $(\"Parse Contract Review\").item.json.obligations + \"\\n\\nQuestions to ask:\\n\" + $(\"Parse Contract Review\").item.json.questions + \"\\n\\nThis is an AI summary, not legal advice.\" }}",
        "options": {},
        "subject": "Your contract summary",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "32d66f49-a555-424f-a782-0cfc7a2289cf",
      "name": "Email Unreadable PDF",
      "type": "n8n-nodes-base.gmail",
      "position": [
        688,
        160
      ],
      "parameters": {
        "sendTo": "={{ $(\"Contract Upload Form\").item.json[\"Your email\"] }}",
        "message": "Your PDF did not contain enough selectable text - it is probably a scan or photo. Please upload a text-based PDF and try again.",
        "options": {},
        "subject": "We could not read your contract",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "86077289-4f2c-478f-b072-d2d704d2ec32",
      "name": "Email Review Failure",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1296,
        160
      ],
      "parameters": {
        "sendTo": "={{ $(\"Contract Upload Form\").item.json[\"Your email\"] }}",
        "message": "Something went wrong while reviewing your document. Please try again, or upload a shorter extract of the contract.",
        "options": {},
        "subject": "We could not review your contract",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "35aa1a4c-728a-4a9d-b5ef-9ba4867eb1c2",
      "name": "Overview Sticky",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -624,
        -288
      ],
      "parameters": {
        "width": 600,
        "height": 676,
        "content": "## Explain any contract PDF in plain language with Gemini and flag risky clauses\n\n### How it works\nMost people sign leases, insurance policies and job contracts without reading them, because the language is impenetrable. Upload the PDF through the built-in n8n form, pick the document type and optionally say what worries you. A Basic LLM Chain with Google Gemini rewrites the contract in plain language, lists the obligations you are taking on, the key dates and notice periods, the costs and penalties, and flags every unusual or one-sided clause with a severity and why it matters - then answers your specific concern by pointing at the relevant clause. Scanned PDFs are rejected up front. Reviews are logged to Google Sheets and a Switch sends a different email by risk: high risk gets a do-not-sign-yet warning with negotiation questions, low risk gets a simple summary.\n\n### Setup\n1. Connect Google Gemini (PaLM) API, Google Sheets and Gmail.\n2. Point the Sheets node at your spreadsheet.\n3. Open the form URL and upload a text-based PDF.\n\n### Customization tips\nAdd your own red-flag list, or route high-risk contracts to a lawyer."
      },
      "typeVersion": 1
    },
    {
      "id": "7a48b829-c8d9-408a-bd0e-12e0e979247b",
      "name": "S1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 864,
        "height": 900,
        "content": "## 1. Upload & validate\nThe built-in n8n form takes the document type, your specific worry and the PDF. Scans without selectable text are rejected with a helpful email."
      },
      "typeVersion": 1
    },
    {
      "id": "250f0e66-0dcc-4dd4-9c47-bd4001be9a89",
      "name": "S2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 628,
        "height": 900,
        "content": "## 2. Plain-language review (Basic LLM Chain)\nGemini returns a plain summary, risk level, obligations, dates, costs, risky clauses with severity, and a direct answer to your concern."
      },
      "typeVersion": 1
    },
    {
      "id": "de68cfc4-38ba-4d9d-bd0d-69d3526276ec",
      "name": "S3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1520,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 500,
        "height": 900,
        "content": "## 3. Parse & log\nFlatten the review into readable sections and append it to your Google Sheets history."
      },
      "typeVersion": 1
    },
    {
      "id": "209b2d1b-f887-484d-9709-737f5bb9d03c",
      "name": "S4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2032,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 552,
        "height": 900,
        "content": "## 4. Route by risk\nHigh risk gets a do-not-sign-yet email with negotiation questions, medium gets the check-list, low gets the plain summary. Every email states it is not legal advice."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "63cbfe24-a946-4aa2-9dd4-0309a752ecb2",
  "nodeGroups": [],
  "connections": {
    "Has Readable Text": {
      "main": [
        [
          {
            "node": "Explain Contract with Gemini",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email Unreadable PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Contract Review": {
      "main": [
        [
          {
            "node": "Route by Risk Level",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Risk Level": {
      "main": [
        [
          {
            "node": "Email Do Not Sign Yet",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email Review Before Signing",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email Plain Summary",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email Generic Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Contract Upload Form": {
      "main": [
        [
          {
            "node": "Extract Contract Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Contract Text": {
      "main": [
        [
          {
            "node": "Has Readable Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Contract Review": {
      "main": [
        [
          {
            "node": "Log Contract Review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Contract Review Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Explain Contract with Gemini",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Explain Contract with Gemini",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Explain Contract with Gemini": {
      "main": [
        [
          {
            "node": "Parse Contract Review",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email Review Failure",
            "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

This workflow collects a contract PDF via an n8n form, extracts its text, uses Google Gemini to generate a structured plain-language review with risk flags, logs the results to Google Sheets, and emails the requester a different summary based on the detected risk level. Receives…

Source: https://n8n.io/workflows/17413/ — original creator credit. Request a take-down →

More Email & Gmail workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Email & Gmail

n8n Graphic Design Team. Uses googleSheets, googleDrive, httpRequest, outputParserStructured. Event-driven trigger; 37 nodes.

Google Sheets, Google Drive, HTTP Request +5
Email & Gmail

AI CV Screening Workflow. Uses lmChatGoogleGemini, gmail, chainLlm, extractFromFile. Event-driven trigger; 7 nodes.

Google Gemini Chat, Gmail, Chain Llm +2
Email & Gmail

AI CV Screening Workflow. Uses lmChatGoogleGemini, gmail, chainLlm, extractFromFile. Event-driven trigger; 7 nodes.

Google Gemini Chat, Gmail, Chain Llm +2
Email & Gmail

This template automates the complete hiring pipeline for digital agencies managing applications across multiple job roles. When a candidate submits a Google Form with their CV, the system scores it wi

OpenRouter Chat, Output Parser Structured, Google Sheets +6
Email & Gmail

This workflow collects job applications via an n8n Form, checks duplicates in Airtable, stores CV files in Google Drive, and uses OpenRouter to score and summarize each CV for an n8n Automation Expert

Form Trigger, Airtable, Form +5