{
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "name": "Transcribe Notion Meeting Recordings with Gladia",
  "tags": [],
  "nodes": [
    {
      "id": "f88accab-3f3d-46b1-bb2f-7838cf413536",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        -592
      ],
      "parameters": {
        "width": 1328,
        "height": 668,
        "content": "## Transcribe Notion Meeting Recordings with Gladia\n\n> \u26a0\ufe0f **Self-hosted n8n only.** Uses the `n8n-nodes-gladia` community node, which is not available on n8n Cloud.\n\n### How it works\n\n1. A new row in your Notion meetings database triggers the workflow.\n2. Gladia transcribes the recording URL with speaker diarization and summarization.\n3. The workflow polls Gladia until the job is done, looping while it is still processing.\n4. The summary and status are written back to the meeting page.\n5. The full transcript is split into Notion-safe blocks and appended to the page.\n6. Any API error or timeout routes to a failure path that marks the page Failed.\n\n### Setup steps\n\n- [ ] Install the `n8n-nodes-gladia` community node (Settings > Community Nodes).\n- [ ] Add a Gladia API credential (key from app.gladia.io).\n- [ ] Add a Notion API credential.\n- [ ] In the trigger, select your meetings database.\n- [ ] Ensure the database has Recording URL (URL), Status (Status, with Transcribed + Failed), and Summary (Text) columns.\n\n### Customization\n\nTune speakers, poll interval, and timeout in the config node: `number_of_speakers`, `wait_seconds`, and `max_attempts` (default timeout 60 attempts x 10s = 10 min)."
      },
      "typeVersion": 1
    },
    {
      "id": "541e69e3-ef2f-4906-8c03-0f7d878b5c22",
      "name": "Trigger and configure",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        96
      ],
      "parameters": {
        "color": 7,
        "width": 428,
        "height": 396,
        "content": "## Trigger and configure\n\nA new Notion database row starts the run. Set `number_of_speakers`, `wait_seconds`, and `max_attempts` here."
      },
      "typeVersion": 1
    },
    {
      "id": "c75eafa7-205b-48ad-bc26-b0313724a800",
      "name": "Transcribe and poll Gladia",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        352,
        96
      ],
      "parameters": {
        "color": 7,
        "width": 900,
        "height": 412,
        "content": "## Transcribe and poll Gladia\n\nGladia is asynchronous: Start Transcription returns a job id, and Get Transcription Result fetches the transcript separately. Route by Status sends `done` onward, routes error or a timeout to the failure path, and loops everything else back to Wait."
      },
      "typeVersion": 1
    },
    {
      "id": "d8341b22-be2c-450d-9a79-546e4dd3fa99",
      "name": "Write results to Notion",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1280,
        96
      ],
      "parameters": {
        "color": 7,
        "width": 752,
        "height": 364,
        "content": "## Write results to Notion\n\nSets Status to Transcribed, writes the summary, then splits the full transcript into Notion-safe blocks (2000-char limit) and appends them to the page."
      },
      "typeVersion": 1
    },
    {
      "id": "1fb4f31f-d653-44f6-8a65-4a274dcb0207",
      "name": "Handle errors and timeouts",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1600,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 380,
        "height": 352,
        "content": "## Handle errors and timeouts\n\nThe two Gladia nodes and the Notion writes use continue-on-error output for API failures, and Route by Status sends timeouts here as well, so both cases mark the page Failed."
      },
      "typeVersion": 1
    },
    {
      "id": "07203490-a437-46de-871d-ef3f1eb8f225",
      "name": "When Meeting Added",
      "type": "n8n-nodes-base.notionTrigger",
      "position": [
        -32,
        304
      ],
      "parameters": {
        "event": "pageAddedToDatabase",
        "simple": true,
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "databaseId": {
          "__rl": true,
          "mode": "id",
          "value": "REPLACE_WITH_MEETINGS_DATABASE_ID"
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "acb16d6d-0fd4-4b34-8099-05ca556a3144",
      "name": "Set Run Config",
      "type": "n8n-nodes-base.set",
      "position": [
        160,
        304
      ],
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "number_of_speakers",
              "type": "number",
              "value": 2
            },
            {
              "id": "a2",
              "name": "wait_seconds",
              "type": "number",
              "value": 10
            },
            {
              "id": "a3",
              "name": "max_attempts",
              "type": "number",
              "value": 60
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "92d47664-2ac5-44a9-a942-00afc93b81d1",
      "name": "Start Transcription",
      "type": "n8n-nodes-gladia.gladia",
      "onError": "continueErrorOutput",
      "position": [
        400,
        304
      ],
      "parameters": {
        "audio_url": "={{ $('When Meeting Added').item.json['Recording URL'] }}",
        "operation": "starttranscription",
        "sentences": true,
        "diarization": true,
        "summarization": true,
        "language_config": {},
        "diarization_config": {
          "mode": "fixed",
          "number_of_speakers": "={{ $('Set Run Config').item.json.number_of_speakers }}"
        },
        "summarization_config": {
          "type": "general"
        }
      },
      "credentials": {
        "gladiaApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "fb54dfa1-3ccf-4ef3-acde-32b34b58fdfc",
      "name": "Wait For Processing",
      "type": "n8n-nodes-base.wait",
      "position": [
        656,
        288
      ],
      "parameters": {
        "unit": "seconds",
        "amount": "={{ $('Set Run Config').item.json.wait_seconds }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "da2798bc-ad75-4de6-8587-55c57b3ef46b",
      "name": "Get Transcription Result",
      "type": "n8n-nodes-gladia.gladia",
      "onError": "continueErrorOutput",
      "position": [
        848,
        288
      ],
      "parameters": {
        "id": "={{ $('Start Transcription').item.json.id }}",
        "operation": "gettranscription"
      },
      "credentials": {
        "gladiaApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f2ef5f5f-f45e-4458-a52b-c15c41aadc43",
      "name": "Route by Status",
      "type": "n8n-nodes-base.switch",
      "position": [
        1088,
        256
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "done",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.status }}",
                    "rightValue": "done"
                  }
                ]
              }
            },
            {
              "outputKey": "failed",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "loose"
                },
                "combinator": "or",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.status }}",
                    "rightValue": "error"
                  },
                  {
                    "operator": {
                      "type": "number",
                      "operation": "gte"
                    },
                    "leftValue": "={{ $runIndex }}",
                    "rightValue": "={{ $('Set Run Config').item.json.max_attempts }}"
                  }
                ]
              }
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "Still Processing"
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "0170541f-4a31-47e7-b2ea-769fddd17982",
      "name": "Update Meeting Page",
      "type": "n8n-nodes-base.notion",
      "onError": "continueErrorOutput",
      "position": [
        1408,
        272
      ],
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('When Meeting Added').item.json.id }}"
        },
        "resource": "databasePage",
        "operation": "update",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Status|status",
              "statusValue": "Transcribed"
            },
            {
              "key": "Summary|rich_text",
              "textContent": "={{ $json.result?.summarization?.results || 'No summary returned' }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "fcb0a04a-1629-4c3e-948a-453f807c551e",
      "name": "Split Transcript Into Blocks",
      "type": "n8n-nodes-base.code",
      "position": [
        1616,
        256
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const transcript = $('Get Transcription Result').item.json.result.transcription.full_transcript || '';\nconst chunks = transcript.match(/[\\s\\S]{1,1900}/g) || [];\nconst blocks = [{ blockType: 'heading_2', text: '\ud83c\udf99\ufe0f Full Transcript' }];\nfor (const chunk of chunks) { blocks.push({ blockType: 'paragraph', text: chunk }); }\nreturn blocks.map(block => ({ json: block }));",
        "language": "javaScript"
      },
      "typeVersion": 2
    },
    {
      "id": "7e71684f-6459-477d-a560-f9810cd3c2db",
      "name": "Append To Page",
      "type": "n8n-nodes-base.notion",
      "onError": "continueErrorOutput",
      "position": [
        1792,
        256
      ],
      "parameters": {
        "blockId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('When Meeting Added').item.json.id }}"
        },
        "blockUi": {
          "blockValues": [
            {
              "type": "={{ $json.blockType }}",
              "textContent": "={{ $json.text }}"
            }
          ]
        },
        "resource": "block",
        "operation": "append"
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "914dc842-9329-4adf-a527-64c228979a6c",
      "name": "Mark Failed",
      "type": "n8n-nodes-base.notion",
      "position": [
        1744,
        672
      ],
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('When Meeting Added').first().json.id }}"
        },
        "resource": "databasePage",
        "operation": "update",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Status|status",
              "statusValue": "Failed"
            },
            {
              "key": "Summary|rich_text",
              "textContent": "={{ '\u26a0\ufe0f Transcription failed or timed out (last status: ' + ($json.status || 'API error') + ')' }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Append To Page": {
      "main": [
        [],
        [
          {
            "node": "Mark Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Run Config": {
      "main": [
        [
          {
            "node": "Start Transcription",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Status": {
      "main": [
        [
          {
            "node": "Update Meeting Page",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark Failed",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait For Processing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Meeting Added": {
      "main": [
        [
          {
            "node": "Set Run Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start Transcription": {
      "main": [
        [
          {
            "node": "Wait For Processing",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Meeting Page": {
      "main": [
        [
          {
            "node": "Split Transcript Into Blocks",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait For Processing": {
      "main": [
        [
          {
            "node": "Get Transcription Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Transcription Result": {
      "main": [
        [
          {
            "node": "Route by Status",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Transcript Into Blocks": {
      "main": [
        [
          {
            "node": "Append To Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}