This workflow corresponds to n8n.io template #9715 — we link there as the canonical source.
This workflow follows the Agent → Google Sheets 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 →
{
"nodes": [
{
"id": "280fc45c-62fe-4108-9bd3-a179d4326d64",
"name": "Extract from File",
"type": "n8n-nodes-base.extractFromFile",
"position": [
256,
128
],
"parameters": {
"options": {},
"operation": "pdf"
},
"typeVersion": 1
},
{
"id": "9da2b9db-6e6a-4c47-8b9a-633e56eb78fc",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
464,
128
],
"parameters": {
"text": "=You are an instructor tasked with generating {{ $('JotForm Trigger').item.json.q5_numberOf }} multiple-choice quiz questions from the following content:\n\n{{ $json.text }}\n\nInstructions:\n- Base all questions strictly on the provided content.\n- {{ $('JotForm Trigger').item.json.q7_quizName }}it should be the title of quiz in the form\n- For each question, generate exactly 4 unique answer options labeled A, B, C, and D.\n- Randomize which option is correct (don\u0092t always make it the same letter).\n- Keep both the questions and options clear and concise.\n- Clearly specify the correct answer using the key \"correct_option\" with the letter of the correct choice (e.g., \"A\").\n- Do not include explanations or extra text \u0097 output JSON only.\n- Ensure valid JSON syntax that can be parsed directly by code.\n\nReturn the output in the exact JSON format below:\n\n[\n {\n \"question\": \"string\",\n \"options\": [\"A. option 1\", \"B. option 2\", \"C. option 3\", \"D. option 4\"],\n \"correct_option\": \"A\"\n }\n]",
"options": {},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.2
},
{
"id": "5c056118-2b7c-458c-9ce9-ff7e5a8f28bc",
"name": "Google Gemini Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
400,
320
],
"parameters": {
"options": {}
},
"typeVersion": 1
},
{
"id": "f7281d5f-4a3a-4bb1-900c-d3fc68f2ee44",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
640,
336
],
"parameters": {
"autoFix": true,
"jsonSchemaExample": "[\n {\n \"question\": \"string\",\n \"options\": [\"A. ...\", \"B. ...\", \"C. ...\", \"D. ...\"],\n \"correct_option\": \"A\"\n }\n]"
},
"typeVersion": 1.3
},
{
"id": "4dd3a242-d3d2-4805-b78d-0048b823147e",
"name": "Split Out",
"type": "n8n-nodes-base.splitOut",
"position": [
816,
128
],
"parameters": {
"options": {},
"fieldToSplitOut": "output"
},
"typeVersion": 1
},
{
"id": "c0e31048-8a0f-4093-9215-a3d5f78c81c3",
"name": "HTTP Request",
"type": "n8n-nodes-base.httpRequest",
"position": [
1440,
128
],
"parameters": {
"url": "https://api.jotform.com/form?apiKey=",
"body": "={{$json}}",
"method": "POST",
"options": {},
"sendBody": true,
"sendQuery": true,
"contentType": "raw",
"sendHeaders": true,
"rawContentType": "application/x-www-form-urlencoded",
"queryParameters": {
"parameters": [
{
"name": "properties[title]",
"value": "Auto-Generated Quiz"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "APIKEY"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "3ed602c6-5550-4797-aade-53e1635081e8",
"name": "Code in JavaScript",
"type": "n8n-nodes-base.code",
"position": [
1232,
128
],
"parameters": {
"jsCode": "const aiData = $('AI Agent').first().json;\n\n// Handle both shapes: [ { output: [...] } ] or { output: [...] }\nconst input = Array.isArray(aiData) ? aiData[0].output : aiData.output;\n\n// Parse if it's a string\nconst quizData = typeof input === 'string' ? JSON.parse(input) : input;\n\n// Validate structure\nif (!Array.isArray(quizData)) {\n throw new Error(\"Expected quizData to be an array, got: \" + typeof quizData);\n}\n\n// ? Dynamic title\nconst title = $('JotForm Trigger').first().json.q7_quizName || \"Auto-Generated Quiz\";\n\nconst body = {\n \"properties[title]\": title,\n \n};\n\n// ? Title centered and styled\nbody[\"properties[title]\"] = title;\nbody[\"properties[titleAlign]\"] = \"center\";\nbody[\"properties[fontFamily]\"] = \"Inter\";\nbody[\"properties[fontColor]\"] = \"#222222\";\n\n// ? General form styling\nbody[\"properties[backgroundColor]\"] = \"#f0f4f8\";\nbody[\"properties[formWidth]\"] = \"800\";\nbody[\"properties[formAlign]\"] = \"center\";\nbody[\"properties[formPadding]\"] = \"40\";\nbody[\"properties[questionSpacing]\"] = \"25\";\n\n// ? Label styling (questions)\nbody[\"properties[labelAlign]\"] = \"top\";\nbody[\"properties[labelWidth]\"] = \"100%\";\nbody[\"properties[labelFontSize]\"] = \"18\";\n\n// ? Option styling (makes radio options display in two columns)\nbody[\"properties[inputTextAlignment]\"] = \"left\";\nbody[\"properties[columns]\"] = \"2\";\nbody[\"properties[radioArrangement]\"] = \"spread\"; // spreads options evenly in 2 columns\n\n// ? Button styling\nbody[\"properties[buttonBackgroundColor]\"] = \"#007bff\";\nbody[\"properties[buttonFontColor]\"] = \"#ffffff\";\n\n// ? Add quiz questions\nquizData.forEach((item, index) => {\n const qIndex = index + 1; // shift by 1 since 0 is the heading\n const formattedOptions = (item.options || []).map(opt => opt.trim()).join('|');\n\n body[`questions[${qIndex}][type]`] = \"control_radio\";\n body[`questions[${qIndex}][text]`] = item.question?.trim() || \"\";\n body[`questions[${qIndex}][options]`] = formattedOptions;\n body[`questions[${qIndex}][correct_option]`] = item.correct_option?.trim() || \"\";\n});\n\nreturn [{ json: body }];\n"
},
"typeVersion": 2
},
{
"id": "48d25cd7-1072-4fce-a0bc-406b36bc0741",
"name": "JotForm Trigger",
"type": "n8n-nodes-base.jotFormTrigger",
"position": [
-112,
128
],
"parameters": {
"form": "252856893250062",
"resolveData": false
},
"typeVersion": 1
},
{
"id": "00bd7928-47b7-4a83-922a-9ce47da2c9df",
"name": "HTTP Request1",
"type": "n8n-nodes-base.httpRequest",
"position": [
96,
128
],
"parameters": {
"url": "={{ $json.fileUpload[0] }}",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "426bb69a-739c-427a-9a74-713aedbf5bff",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-368,
48
],
"parameters": {
"width": 400,
"height": 240,
"content": "## Create a JotForm with Document upload, quiz title and no of questions options"
},
"typeVersion": 1
},
{
"id": "8c6ccd36-136f-4746-8169-fffaf5dac08e",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
48,
48
],
"parameters": {
"width": 160,
"height": 240,
"content": "Download the document\n"
},
"typeVersion": 1
},
{
"id": "4180a4ed-83be-4610-b036-666e37254dba",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
224,
48
],
"parameters": {
"width": 160,
"height": 240,
"content": "Extract Content from the document"
},
"typeVersion": 1
},
{
"id": "f18fbc7d-d400-4eb2-829f-263b9e9f53aa",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
960,
64
],
"parameters": {
"width": 224,
"height": 240,
"content": "Save questions in a google sheet"
},
"typeVersion": 1
},
{
"id": "ccebe5de-4fc5-4ff8-b2f4-04ede361f787",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1376,
64
],
"parameters": {
"height": 240,
"content": "Create a quiz on jotform having AI generated questions"
},
"typeVersion": 1
},
{
"id": "a6904027-8449-41c1-a7bb-0e3b46a101c6",
"name": "Append row in sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
1024,
128
],
"parameters": {
"columns": {
"value": {
"Option A": "={{ $json.options[0] }}",
"Option B": "={{ $json.options[1] }}",
"Option D": "={{ $json.options[3] }}",
"Question": "={{ $json.question }}",
"Option C ": "={{ $json.options[2] }}",
"Correct Answer": "={{ $json.correct_option }}"
},
"schema": [
{
"id": "Question",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Question",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Option A",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Option A",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Option B",
"type": "string",
"display": true,
"required": false,
"displayName": "Option B",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Option C ",
"type": "string",
"display": true,
"required": false,
"displayName": "Option C ",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Option D",
"type": "string",
"display": true,
"required": false,
"displayName": "Option D",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Correct Answer",
"type": "string",
"display": true,
"required": false,
"displayName": "Correct Answer",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1HcnT-czkE8XVMRfeLZLTOuKjmk_51CHEWAkbfU-YOJ0/edit#gid=0",
"cachedResultName": "Questions"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1HcnT-czkE8XVMRfeLZLTOuKjmk_51CHEWAkbfU-YOJ0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1HcnT-czkE8XVMRfeLZLTOuKjmk_51CHEWAkbfU-YOJ0/edit?usp=drivesdk",
"cachedResultName": "Quiz Management"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
}
],
"connections": {
"AI Agent": {
"main": [
[
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "Append row in sheet",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request1": {
"main": [
[
{
"node": "Extract from File",
"type": "main",
"index": 0
}
]
]
},
"JotForm Trigger": {
"main": [
[
{
"node": "HTTP Request1",
"type": "main",
"index": 0
}
]
]
},
"Extract from File": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
},
"Append row in sheet": {
"main": [
[
{
"node": "Code in JavaScript",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
},
{
"node": "Structured Output Parser",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "AI Agent",
"type": "ai_outputParser",
"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.
googleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Instantly turn any document into a shareable online quiz! This n8n workflow automates the entire quiz creation process: a new Jotform submission triggers the flow, the Google Gemini AI extracts key concepts and generates multiple-choice questions with correct answers, saves the…
Source: https://n8n.io/workflows/9715/ — 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 automation is designed to help you generate AI-powered music tracks, cover art, and fully rendered music videos — all triggered from a simple Telegram chat and managed via Google Sheets.
This Shopify AI automation is an advanced n8n-powered workflow that transforms Shopify product collections into SEO-optimized blog articles with images, while maintaining full visibility and control t
LinkedIn URL → Scrape → Match → Screen → Decide, all automated
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.
This workflow is a fully automated YouTube Shorts production pipeline. It takes the structured output from a video digestion workflow (transcript, key moments, metadata) and produces finished, rendere