This workflow corresponds to n8n.io template #9835 — 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 →
{
"id": "KplaPbnfu8G4ZiCK",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Automated Dependency Update Tracking",
"tags": [],
"nodes": [
{
"id": "713381f3-700f-4a63-9d45-1fcb875c89dc",
"name": "When clicking \u2018Execute workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-1136,
-16
],
"parameters": {},
"typeVersion": 1
},
{
"id": "b1a86cf1-b4c7-43ff-8da0-b4ca32b90744",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
864,
144
],
"parameters": {
"width": 288,
"height": 384,
"content": "## \ud83e\udde9 Parse AI Response to Structured Data\n**Action:** \n- Converts AI-generated output into structured JSON fields. \n**Description:** \n- Extracts risk_level and impact_summary. \n- Removes markdown artifacts and trims whitespace. \n- Provides fallback values if parsing fails (\u201cUnknown\u201d risk, \u201cFailed to parse AI output\u201d). \n- Ensures safe and consistent payload for Jira comments and Google Sheets logging.\n"
},
"typeVersion": 1
},
{
"id": "a340ed6c-85ca-48c5-b7ae-a0a4dd93042b",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
384,
432
],
"parameters": {
"width": 368,
"height": 320,
"content": "## \u2699\ufe0f GPT-4o Model Configuration\n**Action:** \n- Configures AI model for accurate risk analysis. \n**Description:** \n- Defines model parameters like temperature, max tokens, and system prompt. \n- Ensures consistent, repeatable results in dependency analysis. \n- Focuses on DevOps context including package criticality and versioning. \n- Optimized for speed, reliability, and cost efficiency.\n"
},
"typeVersion": 1
},
{
"id": "b57a7811-2418-482e-94a1-bb48f79c32ba",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
544,
-480
],
"parameters": {
"width": 272,
"height": 400,
"content": "## \ud83e\udde0 AI-Powered Risk Assessment Analyzer\n**Action:** \n- Uses GPT-4o to assess risk of dependency updates. \n**Description:** \n- Evaluates risk level (Low/Medium/High) and impact summary. \n- Considers dependency type, version changes, security indicators, and breaking change potential. \n- Provides structured JSON for downstream nodes. \n- Reduces manual triage and ensures consistent assessment across issues.\n"
},
"typeVersion": 1
},
{
"id": "45410e03-c687-4c4c-a833-42d1de6433be",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
208,
-432
],
"parameters": {
"width": 288,
"height": 384,
"content": "## \ud83d\udd35 Alert DevOps Team in Slack\n**Action:** \n- Sends a Slack notification about new dependency updates. \n**Description:** \n- Message includes issue key, summary, status, priority, assignee, and Jira link. \n- Notifies DevOps and security teams immediately. \n- Provides formatted, actionable information for rapid response. \n- Creates audit trail of notifications for team transparency.\n"
},
"typeVersion": 1
},
{
"id": "29918ceb-631e-4463-9bb1-d40da0eb3e09",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1248,
160
],
"parameters": {
"width": 304,
"height": 384,
"content": "## \ud83d\udcac Post AI Risk Assessment to Jira Ticket\n**Action:** \n- Adds AI-generated risk assessment as a Jira comment. \n**Description:** \n- Includes risk level, impact summary, and next steps checklist. \n- Provides permanent record for audit and compliance. \n- Allows developers to see AI assessment without leaving Jira. \n- Promotes standardized update validation and quick decision-making.\n"
},
"typeVersion": 1
},
{
"id": "ac6ebd0e-fc6e-4896-9a8c-75eb0d1b816a",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-16,
160
],
"parameters": {
"height": 464,
"content": "## \ud83d\udfe0 Extract Relevant Issue Metadata\n**Action:** \n- Extracts key fields from Jira issues for downstream processing. \n**Description:** \n- Keeps only essential fields: key, summary, assignee, priority, status, URL, and issue links. \n- Removes unnecessary metadata to reduce payload size. \n- Prepares structured JSON for Slack notifications and AI risk assessment. \n- Ensures consistency across all downstream nodes.\n"
},
"typeVersion": 1
},
{
"id": "c81ab400-953c-4860-8069-bd335fae4a55",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-352,
-464
],
"parameters": {
"width": 304,
"height": 416,
"content": "## \ud83d\udd34 Identify Dependency Update Issues\n**Action:** \n- Filters Jira issues to isolate dependency/package updates. \n**Description:** \n- Searches summaries and descriptions for keywords like \u201cupdate,\u201d \u201cbump,\u201d \u201cdependency,\u201d \u201cpackage,\u201d or \u201clibrary.\u201d \n- Case-insensitive matching for maximum coverage. \n- **Matched Path:** Send to AI Risk Analysis. \n- **Unmatched Path:** Skip for efficiency. \n- Reduces noise and focuses AI analysis on relevant security/dependency issues.\n"
},
"typeVersion": 1
},
{
"id": "e5c13a32-8fb8-4a2e-b6da-c40c0cf377b7",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-688,
-544
],
"parameters": {
"height": 512,
"content": "## \u2705 Validate Jira Query Response\n**Action:** \n- Verifies that Jira successfully returned issue data. \n**Description:** \n- Checks if response length > 0 before continuing. \n- **True Path (Data Exists):** Proceeds to filter dependency-related issues. \n- **False Path (No Data/Error):** Routes to error logging. \n- Prevents downstream processing errors from empty datasets. \n- Catches Jira API failures, authentication issues, or permission problems early. \n- Critical quality gate that ensures workflow reliability and proper error handling.\n"
},
"typeVersion": 1
},
{
"id": "d2ce051d-8fb3-47c3-b4f0-333d75a038ae",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
-400,
432
],
"parameters": {
"width": 304,
"height": 336,
"content": "## \ud83d\udfe1 Log Jira Query Failures to Error Sheet\n**Action:** \n- Records Jira API failures or empty responses into a Google Sheet. \n**Description:** \n- Captures error type, message, and timestamp for debugging. \n- Supports identification of recurring API or authentication issues. \n- Separates errors from main workflow to maintain process continuity. \n- Helps troubleshoot integration problems effectively.\n"
},
"typeVersion": 1
},
{
"id": "f2107f52-9a8a-4cee-bf2e-fdd85b6ba1e2",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
-960,
144
],
"parameters": {
"width": 304,
"height": 336,
"content": "## \ud83d\udfe3 Fetch All Active Jira Issues\n**Action:** \n- Retrieves all project issues from Jira for processing. \n**Description:** \n- Connects via Jira API using OAuth or credentials. \n- Pulls keys, summaries, statuses, priorities, assignees, and metadata. \n- Supports pagination or \u201creturnAll: true\u201d for a complete dataset. \n- Forms the base dataset for further analysis.\n"
},
"typeVersion": 1
},
{
"id": "3f725293-56f6-43ee-9aa5-1f5cb72e065e",
"name": "Sticky Note10",
"type": "n8n-nodes-base.stickyNote",
"position": [
1168,
-752
],
"parameters": {
"width": 336,
"height": 400,
"content": "## \ud83d\udcc8 Log Dependency Updates to Tracking Dashboard\n**Action:** \n- Saves all processed dependency updates into a Google Sheet for tracking. \n**Description:** \n- Logs key, summary, assignee, status, risk level, impact summary, and timestamp. \n- Enables historical trend analysis and reporting. \n- Supports dashboards in Looker Studio, Tableau, or Notion. \n- Provides data for compliance audits, risk distribution, and DevOps performance metrics.\n"
},
"typeVersion": 1
},
{
"id": "16c0a63e-1eeb-4408-94f2-11e4b6b74e30",
"name": "Fetch All Active Jira Issues",
"type": "n8n-nodes-base.jira",
"position": [
-864,
-16
],
"parameters": {
"options": {},
"operation": "getAll"
},
"credentials": {
"jiraSoftwareCloudApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "44a7ac98-cc74-465e-986c-e757963f64fd",
"name": "Validate Jira Query Response",
"type": "n8n-nodes-base.if",
"position": [
-592,
-16
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ef3f0536-f084-4c2b-9bf6-7cd172f90035",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $input.all().length > 0 }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "5103029f-44a5-401c-ab8a-0376fbdd8216",
"name": "Log Jira Query Failures to Error Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-320,
256
],
"parameters": {
"columns": {
"value": {},
"schema": [
{
"id": "error_id",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "error_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "error",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "error",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"error_id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1338537721,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Uldk_4BxWbdZTDZxFUeohIfeBmGHHqVEl9Ogb0l6R8Y/edit#gid=1338537721",
"cachedResultName": "error log sheet"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1Uldk_4BxWbdZTDZxFUeohIfeBmGHHqVEl9Ogb0l6R8Y",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Uldk_4BxWbdZTDZxFUeohIfeBmGHHqVEl9Ogb0l6R8Y/edit?usp=drivesdk",
"cachedResultName": "Interviewer Brief Pack "
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "b4b6612d-e0c1-41e6-9a16-b0a47bdbcee4",
"name": "Identify Dependency Update Issues ",
"type": "n8n-nodes-base.filter",
"position": [
-256,
-16
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "c5a26c9f-55d8-4368-9941-2a90ed537287",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "=(\n ($json.fields.summary && (\n $json.fields.summary.toLowerCase().includes(\"update\") ||\n $json.fields.summary.toLowerCase().includes(\"dependency\") ||\n $json.fields.summary.toLowerCase().includes(\"bump\") ||\n $json.fields.summary.toLowerCase().includes(\"package\") ||\n $json.fields.summary.toLowerCase().includes(\"library\")\n )) ||\n ($json.fields.description && (\n $json.fields.description.toLowerCase().includes(\"update\") ||\n $json.fields.description.toLowerCase().includes(\"dependency\") ||\n $json.fields.description.toLowerCase().includes(\"bump\") ||\n $json.fields.description.toLowerCase().includes(\"package\") ||\n $json.fields.description.toLowerCase().includes(\"library\")\n ))\n)\n",
"rightValue": ""
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "f3d4484f-23ad-4034-8c6e-aa006a9a28e4",
"name": "Extract Relevant Issue Metadata",
"type": "n8n-nodes-base.set",
"position": [
48,
-16
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "c7c7c164-5365-44d7-884a-0fe7a607adca",
"name": "key",
"type": "string",
"value": "={{ $json.key }}"
},
{
"id": "aa50207e-78bd-4eff-9fc6-1f8004a225df",
"name": "fields.summary",
"type": "string",
"value": "={{ $json.fields.summary }}"
},
{
"id": "2ec071da-e5da-41be-9d20-c78b391bdc97",
"name": "fields.status",
"type": "object",
"value": "={{ $json.fields.status }}"
},
{
"id": "14963da2-aaf5-44b3-b9c5-14bf919ee1da",
"name": "fields.priority",
"type": "object",
"value": "={{ $json.fields.priority }}"
},
{
"id": "92b47242-2b11-4f0c-852b-56cda94c6194",
"name": "fields.assignee",
"type": "object",
"value": "={{ $json.fields.assignee }}"
},
{
"id": "01721dff-85df-4376-93d6-55c549085c41",
"name": "fields.created",
"type": "string",
"value": "={{ $json.fields.created }}"
},
{
"id": "c470eb6c-b48f-43bd-97dc-2b35832fb956",
"name": "fields.issuelinks",
"type": "array",
"value": "={{ $json.fields.issuelinks }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "ffb64563-2919-4c1d-845c-7dc6e4b19506",
"name": "Alert DevOps Team in Slack",
"type": "n8n-nodes-base.slack",
"position": [
320,
-16
],
"parameters": {
"text": "=*New Dependency Update Found in Jira!*\n*Issue:* {{ $json.fields.summary }}\n*Key:* {{$json[\"key\"]}}\n*Status:* {{$json[\"fields\"][\"status\"][\"name\"]}}\n*Priority:* {{$json[\"fields\"][\"priority\"][\"name\"]}}\n*Assignee:* {{$json[\"fields\"][\"assignee\"][\"displayName\"]}}\n*URL:* {{$json[\"fields\"][\"status\"][\"self\"].replace(\"/rest/api/2/status/\" + $json[\"fields\"][\"status\"][\"id\"], \"/browse/\" + $json[\"key\"])}}\n*Created:* {{$json[\"fields\"][\"created\"]}}",
"user": {
"__rl": true,
"mode": "list",
"value": "U09HMPVD466",
"cachedResultName": "newscctv22"
},
"select": "user",
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "83956de1-806c-4022-82d3-b61ee76bf685",
"name": "AI-Powered Risk Assessment Analyzer",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
576,
-16
],
"parameters": {
"text": "=You are Techdome\u2019s AI DevOps assistant.\nAnalyze this Jira issue update and assign a risk level (Low, Medium, High) with a short reasoning.\n\nHere\u2019s the issue data in JSON:\n{{ JSON.stringify($json) }}\n\nReturn the response only in this JSON format:\n{\n \"risk_level\": \"\",\n \"impact_summary\": \"\"\n}\n",
"options": {
"systemMessage": "="
},
"promptType": "define"
},
"typeVersion": 2.1
},
{
"id": "5320a5e4-a76f-4a2b-ad4e-d6233ac6b047",
"name": "GPT-4o Language Model Configuration",
"type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
"position": [
496,
288
],
"parameters": {
"model": "gpt-4o",
"options": {}
},
"credentials": {
"azureOpenAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "74e29a6b-182b-425f-8969-861ddf2becff",
"name": " Parse AI Response to Structured Data",
"type": "n8n-nodes-base.code",
"position": [
976,
-16
],
"parameters": {
"jsCode": "return items.map(item => {\n try {\n const parsed = JSON.parse(item.json.output.replace(/```json|```/g, \"\").trim());\n return {\n json: {\n ...item.json,\n risk_level: parsed.risk_level,\n impact_summary: parsed.impact_summary\n }\n };\n } catch (error) {\n return {\n json: {\n ...item.json,\n risk_level: \"Unknown\",\n impact_summary: \"Failed to parse AI output\"\n }\n };\n }\n});\n"
},
"typeVersion": 2
},
{
"id": "5fa12a2e-d3c5-496b-820d-d4dad8d9485a",
"name": "Post AI Risk Assessment to Jira Ticket",
"type": "n8n-nodes-base.jira",
"position": [
1312,
-16
],
"parameters": {
"comment": "=\ud83e\udd16 *AI Risk Assessment Report* *Risk Level:* {{$json[\"risk_level\"]}} *Impact Summary:* {{$json[\"impact_summary\"]}} \u2705 *Next Steps:* - [ ] Review dependency changelog - [ ] Run regression tests - [ ] Verify compatibility with core modules - [ ] QA sign-off before merge",
"options": {},
"issueKey": "={{ $('Extract Relevant Issue Metadata').item.json.key }}",
"resource": "issueComment"
},
"credentials": {
"jiraSoftwareCloudApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "04aead69-71ed-4dd0-90d8-f4a0dcb09000",
"name": "Log Dependency Updates to Tracking Dashboard",
"type": "n8n-nodes-base.googleSheets",
"position": [
1312,
-320
],
"parameters": {
"columns": {
"value": {
"Key": "={{ $('Extract Relevant Issue Metadata').item.json.key }}",
"Date": "={{$now}}",
"Status": "={{ $('Extract Relevant Issue Metadata').item.json.fields.status }}",
"Summary": "={{ $('Extract Relevant Issue Metadata').item.json.fields.summary }}",
"Assignee": "={{ $('Extract Relevant Issue Metadata').item.json.fields.assignee }}",
"Risk Level": "={{ $json.risk_level }}",
"Impact Summary": "={{ $json.impact_summary }}"
},
"schema": [
{
"id": "Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Key",
"type": "string",
"display": true,
"required": false,
"displayName": "Key",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Summary",
"type": "string",
"display": true,
"required": false,
"displayName": "Summary",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Risk Level",
"type": "string",
"display": true,
"required": false,
"displayName": "Risk Level",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Impact Summary",
"type": "string",
"display": true,
"required": false,
"displayName": "Impact Summary",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Assignee",
"type": "string",
"display": true,
"required": false,
"displayName": "Assignee",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1144654801,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Uldk_4BxWbdZTDZxFUeohIfeBmGHHqVEl9Ogb0l6R8Y/edit#gid=1144654801",
"cachedResultName": "Automated Dependency Update Tracking"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1Uldk_4BxWbdZTDZxFUeohIfeBmGHHqVEl9Ogb0l6R8Y",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Uldk_4BxWbdZTDZxFUeohIfeBmGHHqVEl9Ogb0l6R8Y/edit?usp=drivesdk",
"cachedResultName": "Interviewer Brief Pack "
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "ad77cf1a-4cea-497d-81f5-c22142cc0bd0",
"connections": {
"Alert DevOps Team in Slack": {
"main": [
[
{
"node": "AI-Powered Risk Assessment Analyzer",
"type": "main",
"index": 0
}
]
]
},
"Fetch All Active Jira Issues": {
"main": [
[
{
"node": "Validate Jira Query Response",
"type": "main",
"index": 0
}
]
]
},
"Validate Jira Query Response": {
"main": [
[
{
"node": "Identify Dependency Update Issues ",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Jira Query Failures to Error Sheet",
"type": "main",
"index": 0
}
]
]
},
"Extract Relevant Issue Metadata": {
"main": [
[
{
"node": "Alert DevOps Team in Slack",
"type": "main",
"index": 0
}
]
]
},
"Identify Dependency Update Issues ": {
"main": [
[
{
"node": "Extract Relevant Issue Metadata",
"type": "main",
"index": 0
}
]
]
},
"AI-Powered Risk Assessment Analyzer": {
"main": [
[
{
"node": " Parse AI Response to Structured Data",
"type": "main",
"index": 0
}
]
]
},
"GPT-4o Language Model Configuration": {
"ai_languageModel": [
[
{
"node": "AI-Powered Risk Assessment Analyzer",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "Fetch All Active Jira Issues",
"type": "main",
"index": 0
}
]
]
},
" Parse AI Response to Structured Data": {
"main": [
[
{
"node": "Post AI Risk Assessment to Jira Ticket",
"type": "main",
"index": 0
},
{
"node": "Log Dependency Updates to Tracking Dashboard",
"type": "main",
"index": 0
}
]
]
},
"Post AI Risk Assessment to Jira Ticket": {
"main": [
[]
]
}
}
}
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.
azureOpenAiApigoogleSheetsOAuth2ApijiraSoftwareCloudApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automates dependency update risk analysis and reporting using Jira, GPT-4o, Slack, and Google Sheets. It continuously monitors Jira for new package or dependency update tickets, uses AI to assess their risk levels (Low, Medium, High), posts structured comments back…
Source: https://n8n.io/workflows/9835/ — 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 workflow intelligently analyzes incoming Gmail emails, classifies intent using GPT-4, and sends real-time Slack notifications while logging structured data into Google Sheets. It provides a smart
Automate Jira backlog management with intelligent cleanup, prioritization, and AI-powered reporting. This workflow scans daily to identify stale issues, missing priorities, and overdue tasks — auto-up
This workflow automates end-to-end validation, assessment, and reporting of n8n workflow JSON templates using Google Drive, Azure OpenAI GPT-4o, Gmail, and Slack. It retrieves workflows from a Drive f
This workflow is an AI-powered virtual cinematography and previs generation pipeline designed for film and VFX production. It transforms a director’s shot description into multiple camera choreography
Automatically capture customer onboarding help requests from Typeform, log them in Google Sheets, validate email addresses, and send a professional HTML welcome email via Gmail. Ensures smooth onboard