This workflow follows the Error Trigger → Gmail 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": [
{
"parameters": {
"folderId": "1gdfgfddfgwlP7pvzmX5Sr33ahLr_8I7rHD",
"title": "={{ ( $('audio_upload').item.binary?.File?.fileName || 'Audio transcript' ).replace(/\\.[^.]+$/, '') }}\n"
},
"type": "n8n-nodes-base.googleDocs",
"typeVersion": 2,
"position": [
704,
-944
],
"id": "e0d74032-abc8-422c-8b51-1ed05266bd71",
"name": "create_empty_doc",
"credentials": {
"googleDocsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "move",
"fileId": {
"__rl": true,
"value": "={{ $json.documentId }}",
"mode": "id"
},
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"folderId": {
"__rl": true,
"value": "1dfgdfgQeUj-UkSoRcretu_FJYIKpL9NPIR9",
"mode": "list",
"cachedResultName": "Audio Transcripts",
"cachedResultUrl": "https://drive.google.com/drive/folders/17ssfssfdUj-UkSoRcretu_FJYIKpL9NPIR9"
}
},
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
1120,
-944
],
"id": "fde94e82-53e3-408c-a4e2-326728bf209d",
"name": "Move file",
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"modelId": {
"__rl": true,
"value": "gpt-4.1",
"mode": "list",
"cachedResultName": "GPT-4.1"
},
"messages": {
"values": [
{
"content": "=Tu es un expert en automation consulting. \nTu re\u00e7ois en entr\u00e9e la transcription brute d\u2019une conversation o\u00f9 le client d\u00e9crit son processus de gestion des e-mails entrants (prospects g\u00e9n\u00e9riques et sp\u00e9cifiques), les difficult\u00e9s rencontr\u00e9es et les ressources documentaires internes fournies. \n\n**Ta mission** : produire un rapport clair et professionnel, en sections num\u00e9rot\u00e9es :\n\n1. **Contexte et Probl\u00e9matique** \n2. **Cat\u00e9gorisation des messages** \n3. **D\u00e9fis techniques** \n4. **Proposition d\u2019architecture d\u2019automatisation** \n5. **B\u00e9n\u00e9fices attendus** \n6. **Prochaines \u00e9tapes**\n\n**Contraintes** : \n- Reformuler de fa\u00e7on synth\u00e9tique, sans rien omettre. \n- Utiliser des paragraphes courts et des listes \u00e0 puces. \n- Ne pas ajouter d\u2019informations externes. \n- L\u2019output doit \u00eatre dans la langue de l\u2019input (fran\u00e7ais ou anglais). \n\n**Input Transcript** : \n{{ $('format_transcript_output').item.json.formattedText || $('format_transcript_output').item.json.text || '' }}\n\n"
},
{
"content": "Tu es un expert en automation consulting, capable de synth\u00e9tiser des \u00e9changes longs en rapports structur\u00e9s, clairs et professionnels, dans la langue de l\u2019input (fran\u00e7ais ou anglais).",
"role": "system"
}
]
},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.openAi",
"typeVersion": 1.8,
"position": [
1376,
-944
],
"id": "bb1c4dd0-8dd3-4b9f-a54b-2ca156645137",
"name": "Message a model",
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// format_transcript_output \u2014 robust: works with multi-input and/or parallel cleanup\n\n// helper: pick first item that has a non-empty json.text\nfunction pickWithText(arr) {\n if (!Array.isArray(arr)) return null;\n for (const it of arr) {\n const t = it?.json?.text;\n if (typeof t === 'string' && t.trim()) return it;\n }\n return null;\n}\n\n// 1) gather items from all available inputs (0..3 to be extra safe)\nconst gathered = [];\nfor (let i = 0; i < 4; i++) {\n try {\n const arr = await $input.all(i);\n if (Array.isArray(arr) && arr.length) gathered.push(...arr);\n } catch (_) { /* input index not present, ignore */ }\n}\n// fallback: at least inspect the first item\nif (gathered.length === 0) {\n const first = $input.first();\n if (first) gathered.push(first);\n}\n\n// 2) try to find json.text on incoming items (works when a transcribe node feeds this directly)\nlet chosen = pickWithText(gathered);\n\n// 3) if still missing, pull from upstream nodes *by name* but safely (no crash if unexecuted)\nfunction tryFromNode(nodeName) {\n try {\n const arr = $items(nodeName, 0, 0) || [];\n return pickWithText(arr);\n } catch (_) {\n return null; // node didn't execute in this branch\n }\n}\nif (!chosen) {\n chosen =\n tryFromNode('transcribe_audio_to_text_small_files') ||\n tryFromNode('transcribe_audio_to_text_big_file');\n}\n\nif (!chosen) {\n throw new Error('No transcript text found on any input or upstream transcribe node.');\n}\n\nconst raw = chosen.json.text;\nconst lang = chosen.json.Language ?? null;\n\n// --- formatting (your original logic) ---\nlet text = raw\n .replace(/\\r/g, '')\n .replace(/[ \\t]+\\n/g, '\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim();\n\nconst sentences =\n text.match(/[^.!?\u00a1\u00bf\u2026]+[.!?\u2026]+(?:[\"'\u201d\u00bb\u2019)\\]]+)?|[^.!?\u00a1\u00bf\u2026]+$/g) || [text];\n\nconst chunkSize = 3;\nconst paragraphs = [];\nfor (let i = 0; i < sentences.length; i += chunkSize) {\n paragraphs.push(sentences.slice(i, i + chunkSize).join(' ').trim());\n}\n\nconst formatted = paragraphs.join('\\n\\n') || text;\n\nreturn [{ json: { text: raw, formattedText: formatted, Language: lang } }];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
448,
-944
],
"id": "8fcfe823-97e5-497b-8ca4-029cfc1e86cb",
"name": "format_transcript_output"
},
{
"parameters": {
"operation": "update",
"documentURL": "={{ $('add_transcript').item.json.documentId }}",
"actionsUi": {
"actionFields": [
{
"action": "insert",
"text": "=\n\n---\n\nR\u00e9sum\u00e9 de la conversation : \n\n{{ $json.message.content }}"
}
]
}
},
"type": "n8n-nodes-base.googleDocs",
"typeVersion": 2,
"position": [
1728,
-944
],
"id": "1a0d8a2e-4e29-4bd2-a8a0-28f7640f2f87",
"name": "add_summary",
"credentials": {
"googleDocsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "update",
"documentURL": "={{ $json.id }}",
"actionsUi": {
"actionFields": [
{
"action": "insert",
"text": "={{ $('format_transcript_output').item.json.formattedText }}"
}
]
}
},
"type": "n8n-nodes-base.googleDocs",
"typeVersion": 2,
"position": [
912,
-944
],
"id": "25914485-3084-4668-8310-b336d8cab89c",
"name": "add_transcript",
"credentials": {
"googleDocsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"sendTo": "test@gmail.com",
"subject": "=R\u00e9sum\u00e9 du transcript - {{ $('audio_upload').item.json.File.filename }}",
"message": "=Ex\u00e9cution termin\u00e9e ! Voici le document : https://docs.google.com/document/d/{{ $node[\"create_empty_doc\"].json[\"id\"] }}/edit",
"options": {
"appendAttribution": false
}
},
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
1952,
-944
],
"id": "1feced92-e0a7-436d-99f1-0987bc73f9ff",
"name": "Send a message",
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"chatId": "1953356832",
"text": "=Transcription finie ! \ud83d\udcc4 \nAcc\u00e8de au r\u00e9sultat ici : https://docs.google.com/document/d/{{ $node[\"create_empty_doc\"].json[\"id\"] }}/edit",
"additionalFields": {
"appendAttribution": false
}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
2176,
-944
],
"id": "1142b90a-7d63-461d-87fd-75247e8bfb9e",
"name": "Send a text message",
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"content": "## Create text file\n- Create the google doc file \n- populate it with the formatted transcribe\n- Move the file to the right folder\n",
"height": 448,
"width": 640,
"color": 5
},
"type": "n8n-nodes-base.stickyNote",
"position": [
640,
-1184
],
"typeVersion": 1,
"id": "180ed47e-2039-419f-9a76-0466d0985ade",
"name": "Sticky Note1"
},
{
"parameters": {
"content": "## Formatted transcribe summary\n- Get a professional summary of the transcribe\n",
"height": 448,
"width": 384,
"color": 6
},
"type": "n8n-nodes-base.stickyNote",
"position": [
1296,
-1184
],
"typeVersion": 1,
"id": "ae592999-51dc-417c-b100-6faefe23f554",
"name": "Sticky Note2"
},
{
"parameters": {
"content": "## Append Summary + Notification\n- Append the transcribe summary to google doc\n- Notify the user by email + Telegram\n",
"height": 448,
"width": 704,
"color": 4
},
"type": "n8n-nodes-base.stickyNote",
"position": [
1696,
-1184
],
"typeVersion": 1,
"id": "d385d242-5ff5-4f38-924b-7d1e969f8856",
"name": "Sticky Note3"
},
{
"parameters": {
"operation": "write",
"fileName": "=/tmp/in_{{$execution.id}}",
"dataPropertyName": "={{ $json.binaryField || 'File' }}",
"options": {}
},
"type": "n8n-nodes-base.readWriteFile",
"typeVersion": 1,
"position": [
-1248,
-768
],
"id": "ae3e1c03-7112-4b76-9eea-c842fecd040a",
"name": "write_original_to_disk"
},
{
"parameters": {
"fileSelector": "=/tmp/out_{{$execution.id}}.mp3",
"options": {}
},
"type": "n8n-nodes-base.readWriteFile",
"typeVersion": 1,
"position": [
-800,
-768
],
"id": "cc195282-01a7-4fb2-bcdc-2d9eb3b407ec",
"name": "read_downconverted"
},
{
"parameters": {
"command": "=ffmpeg -y -hide_banner -loglevel error \\\n -i \"/tmp/in_{{$execution.id}}\" \\\n -ac 1 -ar 16000 -c:a libmp3lame -b:a 64k \\\n \"/tmp/out_{{$execution.id}}.mp3\"\n"
},
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
-1024,
-768
],
"id": "bddf8673-7229-488f-b54d-76abdef1a1ac",
"name": "ffmpeg_downconvert"
},
{
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.sizeBytes }}",
"value2": 24500000
}
]
}
},
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
-1488,
-944
],
"id": "bfe1771f-d890-47c2-9bca-63bca1b2aff4",
"name": "IF size <= ~24.5MB"
},
{
"parameters": {
"jsCode": "// probe_size1 \u2014 runs once, measures uploaded file size in bytes\nconst inItem = $input.first();\n\nif (!inItem.binary || Object.keys(inItem.binary).length === 0) {\n throw new Error('No binary file on input item. Check the form file field.');\n}\n\n// Use the actual binary key from the form; fallback to 'File'\nconst binName = Object.keys(inItem.binary)[0] || 'File';\n\n// Get exact size\nconst buf = await this.helpers.getBinaryDataBuffer(0, binName);\n\n// Return one item, keep the binary, expose size + language + bin name\nreturn [{\n json: {\n sizeBytes: buf.length,\n Language: inItem.json?.Language,\n binaryField: binName\n },\n binary: inItem.binary\n}];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-1696,
-944
],
"id": "4a2dff3e-6a1d-443c-96b7-b64acc024024",
"name": "probe_size"
},
{
"parameters": {
"jsCode": "// probe_size_after \u2014 robust: works with 'File' or any binary key (e.g. 'data')\nconst inItem = $input.first();\nconst binKeys = Object.keys(inItem.binary || {});\nif (binKeys.length === 0) {\n throw new Error('No binary found on input item.');\n}\n\n// Prefer 'File' if present, otherwise use the first key (e.g. 'data')\nconst binName = binKeys.includes('File') ? 'File' : binKeys[0];\n\nconst buf = await this.helpers.getBinaryDataBuffer(0, binName);\nreturn [{\n json: {\n sizeBytesAfter: buf.length,\n Language: inItem.json?.Language,\n binaryField: binName\n },\n binary: inItem.binary\n}];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-608,
-768
],
"id": "66858c13-5afe-471c-89c8-4fd46fd9b72e",
"name": "probe_size_after"
},
{
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.sizeBytesAfter }}",
"value2": 25000000
}
]
}
},
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
-416,
-768
],
"id": "2714a88c-e2a6-4c8e-934a-669e5e70f3f3",
"name": "IF size <= 25MB (after)"
},
{
"parameters": {
"errorMessage": "Audio file remains above 25 MB after down-conversion. Please try a shorter clip or compress more aggressively."
},
"type": "n8n-nodes-base.stopAndError",
"typeVersion": 1,
"position": [
208,
-384
],
"id": "24e49664-c077-4cab-922f-e2a00a8b84ff",
"name": "Stop and Error"
},
{
"parameters": {
"command": "=rm -f -- \"/tmp/in_{{$execution.id}}\" \"/tmp/out_{{$execution.id}}.mp3\" \"/tmp/out_{{$execution.id}}.webm\" 2>/dev/null || true\n\n"
},
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
-16,
-384
],
"id": "8d5397df-9ee6-4325-bb03-92c74f0fc7ac",
"name": "cleanup_tmp"
},
{
"parameters": {},
"type": "n8n-nodes-base.errorTrigger",
"typeVersion": 1,
"position": [
-1904,
-576
],
"id": "3f840ff3-42e8-4b87-84dc-3e933f80f269",
"name": "Error Trigger"
},
{
"parameters": {
"command": "=rm -f -- \"/tmp/in_{{$execution.id}}\" \"/tmp/out_{{$execution.id}}.mp3\" \"/tmp/out_{{$execution.id}}.webm\" 2>/dev/null || true\n\n"
},
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
160,
-800
],
"id": "2c1f1a03-b56e-476c-889e-8f905f65e383",
"name": "cleanup_tmp3"
},
{
"parameters": {
"command": "=rm -f -- \"/tmp/in_{{$execution.id}}\" \"/tmp/out_{{$execution.id}}.mp3\" \"/tmp/out_{{$execution.id}}.webm\" 2>/dev/null || true\n\n"
},
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
-1696,
-576
],
"id": "68590a60-11e4-43e0-8458-93542e6edc02",
"name": "cleanup_tmp1"
},
{
"parameters": {
"authentication": "basicAuth",
"formTitle": "Audio Transcript",
"formDescription": "Upload an audio file and get the transcript",
"formFields": {
"values": [
{
"fieldLabel": "File",
"fieldType": "file",
"multipleFiles": false,
"acceptFileTypes": ".m4a, .mp4, .mp3, .wav, .ogg",
"requiredField": true
},
{
"fieldLabel": "Language",
"fieldType": "dropdown",
"fieldOptions": {
"values": [
{
"option": "fr"
},
{
"option": "en"
},
{
"option": "es"
}
]
},
"requiredField": true
}
]
},
"options": {}
},
"type": "n8n-nodes-base.formTrigger",
"typeVersion": 2.2,
"position": [
-1904,
-944
],
"id": "2efb9fd2-c74e-4951-a49f-53d4a929d5ab",
"name": "audio_upload",
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"content": "## File upload and size check\n- Get the audio file\n- Check the size \n",
"height": 448,
"width": 640,
"color": 5
},
"type": "n8n-nodes-base.stickyNote",
"position": [
-1968,
-1168
],
"typeVersion": 1,
"id": "a9501b3e-330d-4bfb-89be-9fd61966d7b2",
"name": "Sticky Note4"
},
{
"parameters": {
"content": "## Downsize if too big, temporary upload\n- Downsize the file using ffmpeg\n- Upload it on the server\n",
"height": 544,
"width": 1120,
"color": 2
},
"type": "n8n-nodes-base.stickyNote",
"position": [
-1296,
-1072
],
"typeVersion": 1,
"id": "44597d71-363a-46b1-a0d2-5d634a1ab264",
"name": "Sticky Note5"
},
{
"parameters": {
"content": "## Error handler\n- Clean up files\n",
"height": 432,
"width": 640,
"color": 3
},
"type": "n8n-nodes-base.stickyNote",
"position": [
-112,
-576
],
"typeVersion": 1,
"id": "f43bb185-5d29-4605-b14f-73371ee668fa",
"name": "Sticky Note6"
},
{
"parameters": {
"content": "## Error handler\n- Clean up files\n",
"height": 320,
"width": 640,
"color": 3
},
"type": "n8n-nodes-base.stickyNote",
"position": [
-1968,
-704
],
"typeVersion": 1,
"id": "9ead9f28-f8a7-451e-8a0c-f021b6df9533",
"name": "Sticky Note7"
},
{
"parameters": {
"resource": "audio",
"operation": "transcribe",
"binaryPropertyName": "=data",
"options": {
"language": "={{ $json.Language }}"
}
},
"type": "@n8n/n8n-nodes-langchain.openAi",
"typeVersion": 1.8,
"position": [
-112,
-800
],
"id": "2c09451e-0dcb-4545-a97a-054b29bb0cb9",
"name": "transcribe_audio_to_text_big_file",
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resource": "audio",
"operation": "transcribe",
"binaryPropertyName": "=File",
"options": {
"language": "={{ $json.Language }}"
}
},
"type": "@n8n/n8n-nodes-langchain.openAi",
"typeVersion": 1.8,
"position": [
-112,
-1008
],
"id": "affa925b-fc14-4072-9994-63c5e46e80e9",
"name": "transcribe_audio_to_text_small_files",
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"content": "## Get the text content\n- Get the audio file\n- Transcribe the audio to text\n- Parse the text to paragraphs to facilitate reading\n",
"height": 592,
"width": 784
},
"type": "n8n-nodes-base.stickyNote",
"position": [
-160,
-1184
],
"typeVersion": 1,
"id": "f5a91dc2-2569-48e3-a447-fc9ae25ad156",
"name": "Sticky Note"
}
],
"connections": {
"create_empty_doc": {
"main": [
[
{
"node": "add_transcript",
"type": "main",
"index": 0
}
]
]
},
"Move file": {
"main": [
[
{
"node": "Message a model",
"type": "main",
"index": 0
}
]
]
},
"Message a model": {
"main": [
[
{
"node": "add_summary",
"type": "main",
"index": 0
}
]
]
},
"format_transcript_output": {
"main": [
[
{
"node": "create_empty_doc",
"type": "main",
"index": 0
}
]
]
},
"add_summary": {
"main": [
[
{
"node": "Send a message",
"type": "main",
"index": 0
}
]
]
},
"add_transcript": {
"main": [
[
{
"node": "Move file",
"type": "main",
"index": 0
}
]
]
},
"Send a message": {
"main": [
[
{
"node": "Send a text message",
"type": "main",
"index": 0
}
]
]
},
"write_original_to_disk": {
"main": [
[
{
"node": "ffmpeg_downconvert",
"type": "main",
"index": 0
}
]
]
},
"read_downconverted": {
"main": [
[
{
"node": "probe_size_after",
"type": "main",
"index": 0
}
]
]
},
"ffmpeg_downconvert": {
"main": [
[
{
"node": "read_downconverted",
"type": "main",
"index": 0
}
]
]
},
"IF size <= ~24.5MB": {
"main": [
[
{
"node": "transcribe_audio_to_text_small_files",
"type": "main",
"index": 0
}
],
[
{
"node": "write_original_to_disk",
"type": "main",
"index": 0
}
]
]
},
"probe_size": {
"main": [
[
{
"node": "IF size <= ~24.5MB",
"type": "main",
"index": 0
}
]
]
},
"probe_size_after": {
"main": [
[
{
"node": "IF size <= 25MB (after)",
"type": "main",
"index": 0
}
]
]
},
"IF size <= 25MB (after)": {
"main": [
[
{
"node": "transcribe_audio_to_text_big_file",
"type": "main",
"index": 0
}
],
[
{
"node": "cleanup_tmp",
"type": "main",
"index": 0
}
]
]
},
"cleanup_tmp": {
"main": [
[
{
"node": "Stop and Error",
"type": "main",
"index": 0
}
]
]
},
"Error Trigger": {
"main": [
[
{
"node": "cleanup_tmp1",
"type": "main",
"index": 0
}
]
]
},
"cleanup_tmp3": {
"main": [
[
{
"node": "format_transcript_output",
"type": "main",
"index": 0
}
]
]
},
"audio_upload": {
"main": [
[
{
"node": "probe_size",
"type": "main",
"index": 0
}
]
]
},
"transcribe_audio_to_text_big_file": {
"main": [
[
{
"node": "cleanup_tmp3",
"type": "main",
"index": 0
}
]
]
},
"transcribe_audio_to_text_small_files": {
"main": [
[
{
"node": "format_transcript_output",
"type": "main",
"index": 0
}
]
]
}
},
"meta": {
"templateCredsSetupCompleted": true
}
}
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.
gmailOAuth2googleDocsOAuth2ApigoogleDriveOAuth2ApihttpBasicAuthopenAiApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Transcript Audio To Text. Uses googleDocs, googleDrive, openAi, gmail. Event-driven trigger; 31 nodes.
Source: https://gist.github.com/agencyneoweb-star/996a80f57c913ab696193675f1313ce1 — 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.
Extract content from PDFs, generate two different test versions with AI, and create formatted Google Docs with automated email delivery. This workflow extracts text from PDF teaching materials, uses O
This workflow provides an automated pipeline for processing medical X-ray images using VLM Run (model: ), and distributing the AI-generated analysis to multiple channels—email, Telegram, and Google Dr
Use cases are many: send branded quotations to new leads after a discovery call, distribute pricing proposals to inbound form submissions, or push service packages to prospects. All without manually c
What it is An automated LinkedIn content system that takes a simple form (idea + optional file), generates LinkedIn posts with OpenAI, stores them in Notion, builds Google Slides carousels, and auto-p
Automatically analyze your full sports performance evolution using your Strava activities, enriched with AI insights and delivered directly to your email — all powered by your own n8n instance.