AutomationFlowsWeb Scraping › Chatbot — Website Chat

Chatbot — Website Chat

Chatbot — Website Chat. Uses httpRequest. Webhook trigger; 12 nodes.

Webhook trigger★★★★☆ complexity12 nodesHTTP Request
Web Scraping Trigger: Webhook Nodes: 12 Complexity: ★★★★☆ Added:

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
{
  "name": "Chatbot \u2014 Website Chat",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "website-chat",
        "responseMode": "lastNode",
        "options": {
          "rawBody": false
        }
      },
      "id": "node-webhook-website",
      "name": "Webhook \u2014 Website Chat",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        240,
        300
      ],
      "notes": "URL p\u00fablica: https://SEU_DOMINIO/webhook/website-chat\nO widget JS faz POST aqui diretamente."
    },
    {
      "parameters": {
        "jsCode": "// Valida e normaliza o payload do widget de chat\nconst body = $input.first().json.body;\n\nconst required = ['visitor_id', 'text'];\nfor (const field of required) {\n  if (!body[field]) {\n    throw new Error(`Campo obrigat\u00f3rio ausente: ${field}`);\n  }\n}\n\nif (body.text.length > 4096) {\n  throw new Error('Mensagem muito longa');\n}\n\nreturn [{\n  json: {\n    external_user_id: body.visitor_id,\n    channel: 'website',\n    text: body.text.trim(),\n    user_name: body.name || null,\n    user_email: body.email || null,\n    metadata: {\n      page_url: body.page_url || null,\n      user_agent: body.user_agent || null,\n      session_id: body.session_id || null\n    }\n  }\n}];"
      },
      "id": "node-validate-payload",
      "name": "Valida e normaliza payload",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "url": "http://api:8000/api/v1/messages/incoming",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Webhook-Secret",
              "value": "={{ $env.N8N_WEBHOOK_SECRET }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"external_user_id\": \"{{ $json.external_user_id }}\",\n  \"channel\": \"{{ $json.channel }}\",\n  \"text\": \"{{ $json.text }}\",\n  \"user_name\": {{ $json.user_name ? '\"' + $json.user_name + '\"' : 'null' }},\n  \"user_email\": {{ $json.user_email ? '\"' + $json.user_email + '\"' : 'null' }},\n  \"metadata\": {{ JSON.stringify($json.metadata) }}\n}",
        "options": {
          "timeout": 15000,
          "response": {
            "response": {
              "fullResponse": false
            }
          }
        }
      },
      "id": "node-call-backend",
      "name": "Chama Backend Python",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        680,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "leftValue": "={{ $json.human_handoff }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ]
        }
      },
      "id": "node-check-handoff",
      "name": "Handoff para humano?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        900,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Resposta normal do bot \u2014 retorna JSON ao widget\nconst data = $input.first().json;\nreturn [{\n  json: {\n    ok: true,\n    conversation_id: data.conversation_id,\n    message_id: data.message_id,\n    reply: data.reply,\n    intent: data.intent,\n    human_handoff: false,\n    tokens_used: data.tokens_used\n  }\n}];"
      },
      "id": "node-format-bot-reply",
      "name": "Formata resposta do bot",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1120,
        200
      ]
    },
    {
      "parameters": {
        "jsCode": "// Resposta de handoff \u2014 widget exibe banner de transfer\u00eancia\nconst data = $input.first().json;\nreturn [{\n  json: {\n    ok: true,\n    conversation_id: data.conversation_id,\n    message_id: data.message_id,\n    reply: data.reply,\n    intent: data.intent,\n    human_handoff: true,\n    handoff_message: 'Um agente humano ir\u00e1 continuar seu atendimento em breve. Por favor, aguarde.',\n    tokens_used: data.tokens_used\n  }\n}];"
      },
      "id": "node-format-handoff-reply",
      "name": "Formata resposta de handoff",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1120,
        400
      ]
    },
    {
      "parameters": {
        "jsCode": "// Notifica equipe sobre handoff via website\n// Substitua pelo n\u00f3 Slack, Email, ou Zendesk conforme seu stack\nconst data = $('Chama Backend Python').first().json;\nconsole.log('HANDOFF WEBSITE', JSON.stringify({\n  conversation_id: data.conversation_id,\n  intent: data.intent,\n  urgency_score: data.urgency_score,\n  ts: new Date().toISOString()\n}));\n\n// Exemplo: chamar webhook do Slack\n// await $http.post(process.env.SLACK_WEBHOOK_URL, {\n//   text: `\ud83d\udea8 Handoff solicitado\\nConversa: ${data.conversation_id}\\nUrg\u00eancia: ${data.urgency_score}`\n// });\n\nreturn $input.all();"
      },
      "id": "node-notify-team",
      "name": "Notifica equipe",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1340,
        400
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "node-respond-widget",
      "name": "Responde ao widget",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        1560,
        200
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "node-respond-widget-handoff",
      "name": "Responde ao widget (handoff)",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        1560,
        400
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={ \"ok\": false, \"error\": \"Erro interno. Tente novamente.\" }",
        "options": {
          "responseCode": 500
        }
      },
      "id": "node-error-response",
      "name": "Responde erro ao widget",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        680,
        520
      ]
    },
    {
      "parameters": {
        "jsCode": "const error = $input.first().json;\nconsole.error('WEBSITE_CHAT_ERROR', JSON.stringify({\n  error: error.message || 'Unknown error',\n  ts: new Date().toISOString()\n}));\nreturn $input.all();"
      },
      "id": "node-log-error",
      "name": "Loga erro",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        460,
        520
      ]
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconsole.log(JSON.stringify({\n  event: 'website_chat_processed',\n  conversation_id: data.conversation_id,\n  intent: data.intent,\n  urgency_score: data.urgency_score,\n  tokens_used: data.tokens_used,\n  human_handoff: data.human_handoff,\n  ts: new Date().toISOString()\n}));\nreturn $input.all();"
      },
      "id": "node-log-success",
      "name": "Log de auditoria",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1340,
        200
      ]
    }
  ],
  "connections": {
    "Webhook \u2014 Website Chat": {
      "main": [
        [
          {
            "node": "Valida e normaliza payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Valida e normaliza payload": {
      "main": [
        [
          {
            "node": "Chama Backend Python",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chama Backend Python": {
      "main": [
        [
          {
            "node": "Handoff para humano?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Handoff para humano?": {
      "main": [
        [
          {
            "node": "Formata resposta do bot",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Formata resposta de handoff",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Formata resposta do bot": {
      "main": [
        [
          {
            "node": "Log de auditoria",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Formata resposta de handoff": {
      "main": [
        [
          {
            "node": "Notifica equipe",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log de auditoria": {
      "main": [
        [
          {
            "node": "Responde ao widget",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notifica equipe": {
      "main": [
        [
          {
            "node": "Responde ao widget (handoff)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loga erro": {
      "main": [
        [
          {
            "node": "Responde erro ao widget",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "errorWorkflow": ""
  },
  "meta": {
    "description": "Recebe mensagens do widget de chat do website, processa via backend Python com IA e retorna resposta JSON ao widget. Suporta handoff para humano."
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Chatbot — Website Chat. Uses httpRequest. Webhook trigger; 12 nodes.

Source: https://github.com/ElsonGomes-pgr/ChatBot-inteligente/blob/6621826bab9880418c32845d60007e2dfb9f10ad/chatbot-backend/n8n/workflow-website.json — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

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

Web Scraping

This n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di

n8n, Execute Workflow Trigger, HTTP Request +1
Web Scraping

This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .

HTTP Request, Ssh
Web Scraping

eek-Go v2 (Batch-Then-Review). Uses httpRequest. Webhook trigger; 75 nodes.

HTTP Request
Web Scraping

This workflow receives webhook requests from a content calendar and uses the X API v2 to publish text posts, threads, image/video posts, and polls, as well as delete existing posts and run a credentia

HTTP Request
Web Scraping

This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c

HTTP Request