AutomationFlowsSlack & Telegram › Sync Hubspot Contacts to Klaviyo and Log Activity to Slack and Google Sheets

Sync Hubspot Contacts to Klaviyo and Log Activity to Slack and Google Sheets

ByAkshay Chug @akshaychug on n8n.io

This workflow receives new HubSpot contact webhooks, fetches full contact details, maps lifecycle stages to Klaviyo lists, creates/updates the Klaviyo profile, adds it to the right list, then notifies Slack and logs the sync to Google Sheets. Receives a webhook request from…

Webhook trigger★★★★☆ complexity13 nodesHTTP RequestSlackGoogle Sheets
Slack & Telegram Trigger: Webhook Nodes: 13 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #15940 — we link there as the canonical source.

This workflow follows the Google Sheets → HTTP Request 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 →

Download .json
{
  "id": "nvpImrURIU8lwmmG",
  "name": "HubSpot to Klaviyo Sync: Auto-Enrich Contacts and Trigger Email Sequences",
  "tags": [],
  "nodes": [
    {
      "id": "fae2888a-b2c5-44a8-8658-2e36a15230ac",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "color": 0,
        "width": 480,
        "height": 1108,
        "content": "## HubSpot to Klaviyo Sync Bridge using n8n\n\nIf you run HubSpot for CRM and Klaviyo for email, you know the pain -- new contacts sit in HubSpot without ever reaching Klaviyo, sequences never fire on time, and your lists go stale. This workflow fixes that permanently.\n\n### How it works\n\n1. HubSpot fires a webhook the moment a new contact is created in your account.\n2. The workflow fetches the full contact record from HubSpot including lifecycle stage, company, deal value, and any custom properties.\n3. A Code node maps the HubSpot contact data to the correct Klaviyo list and tag based on lifecycle stage -- Lead, MQL, SQL, or Customer.\n4. The contact is created or updated in Klaviyo via API with all mapped properties and the correct list assignment.\n5. The appropriate Klaviyo flow is triggered for that contact based on their lifecycle stage -- for example, a welcome sequence for new leads or an onboarding sequence for new customers.\n6. A confirmation is sent to a Slack channel with the contact name, stage, and which Klaviyo list they were added to.\n7. Every sync is logged to Google Sheets with a timestamp, contact details, stage, and Klaviyo list name.\n\n### Setup steps\n\n- [ ] **HubSpot webhook** -- In HubSpot go to Settings, Integrations, Private Apps or use the Webhooks API. Create a webhook that fires on Contact Created and paste the URL from the Receive HubSpot Contact node.\n- [ ] **HubSpot API key** -- Create a Private App in HubSpot with read access to Contacts. Copy the access token and add it to the Configure Mapping and Settings node.\n- [ ] **Klaviyo API key** -- In Klaviyo go to Account, Settings, API Keys and create a Private API Key with full access. Add it to the Configure Mapping and Settings node.\n- [ ] **Klaviyo list IDs** -- In Klaviyo go to Lists and Segments. Copy the List ID for each list you want to sync to (Lead, MQL, SQL, Customer) and add them to the Settings node.\n- [ ] **Slack** -- Connect your Slack account in Notify Sync Complete and set your channel. Right-click and Disable if unused.\n- [ ] **Google Sheets** -- Create a sheet called Klaviyo Sync Log with columns: Timestamp, Name, Email, Company, HubSpot Stage, Klaviyo List, Status. Connect your Google account in Log Sync to Sheets.\n- [ ] Activate the workflow and create a test contact in HubSpot to verify the sync works end to end.\n\n### Customization\n\nAdd more lifecycle stage mappings in the Map to Klaviyo List node to match your exact HubSpot pipeline. Add a branch to also update existing Klaviyo profiles when a HubSpot contact updates their lifecycle stage. Extend with a Clearbit or Apollo HTTP Request to enrich company data before syncing."
      },
      "typeVersion": 1
    },
    {
      "id": "9659a586-7b3a-403b-a3e0-5ad0f92bde6f",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 440,
        "height": 440,
        "content": "## Receive and fetch HubSpot contact\n\nHubSpot fires a webhook on Contact Created. A second HTTP Request fetches the full contact record including all properties, lifecycle stage, and company data from the HubSpot API."
      },
      "typeVersion": 1
    },
    {
      "id": "9dcec29c-3b27-4a22-bfe2-be76f1fbf53e",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1040,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 428,
        "height": 448,
        "content": "## Map contact to Klaviyo list\n\nA Code node reads the HubSpot lifecycle stage and maps it to the correct Klaviyo list ID and tag. Edit the Settings node to add your actual Klaviyo list IDs -- no other node needs changing."
      },
      "typeVersion": 1
    },
    {
      "id": "c4050a43-5e9b-48ce-a5e9-657165593f8b",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1520,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 444,
        "content": "## Sync to Klaviyo\n\nTwo HTTP Requests handle the Klaviyo side: the first creates or updates the profile with all HubSpot properties, the second adds the profile to the correct list. Both use your Klaviyo Private API key."
      },
      "typeVersion": 1
    },
    {
      "id": "b1ccb5f8-fb5d-48d1-a000-81d70718e28a",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2064,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 344,
        "height": 584,
        "content": "## Alert and log\n\nSends a Slack notification confirming which Klaviyo list the contact was added to, then logs the full sync record to Google Sheets. Slack is optional -- right-click and Disable if unused."
      },
      "typeVersion": 1
    },
    {
      "id": "586bb3a3-d12c-46a2-b039-1ce952aa792d",
      "name": "Receive HubSpot Contact",
      "type": "n8n-nodes-base.webhook",
      "position": [
        592,
        272
      ],
      "parameters": {
        "path": "hubspot-new-contact",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "lastNode"
      },
      "typeVersion": 2
    },
    {
      "id": "4ef295f6-b095-45bb-b94b-869be38cb527",
      "name": "Configure Mapping and Settings",
      "type": "n8n-nodes-base.code",
      "position": [
        832,
        272
      ],
      "parameters": {
        "jsCode": "// ================================================\n//  EDIT THIS NODE -- all your settings live here\n// ================================================\n\nconst HUBSPOT_ACCESS_TOKEN = 'YOUR_HUBSPOT_ACCESS_TOKEN';\nconst KLAVIYO_API_KEY      = 'YOUR_KLAVIYO_API_KEY';\n\n// Map HubSpot lifecycle stages to Klaviyo list IDs\n// Find list IDs in Klaviyo under Lists and Segments\nconst LIST_MAP = {\n  'lead':       'YOUR_KLAVIYO_LEADS_LIST_ID',\n  'marketingqualifiedlead': 'YOUR_KLAVIYO_MQL_LIST_ID',\n  'salesqualifiedlead':     'YOUR_KLAVIYO_SQL_LIST_ID',\n  'customer':   'YOUR_KLAVIYO_CUSTOMERS_LIST_ID',\n  'subscriber': 'YOUR_KLAVIYO_LEADS_LIST_ID',\n  'default':    'YOUR_KLAVIYO_LEADS_LIST_ID'\n};\n\n// ================================================\n//  DO NOT EDIT BELOW THIS LINE\n// ================================================\n\nconst body = $input.first().json.body || $input.first().json;\nconst contactId = body.objectId || body.vid || body.id || body.contactId || '';\n\nreturn [{\n  json: {\n    hubspot_token: HUBSPOT_ACCESS_TOKEN,\n    klaviyo_key:   KLAVIYO_API_KEY,\n    list_map:      LIST_MAP,\n    contact_id:    String(contactId),\n    timestamp:     new Date().toISOString()\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "d7df539b-2a45-41ee-8550-9122f940b719",
      "name": "Fetch Full HubSpot Contact",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1072,
        272
      ],
      "parameters": {
        "url": "={{ 'https://api.hubapi.com/crm/v3/objects/contacts/' + $json.contact_id + '?properties=email,firstname,lastname,company,phone,lifecyclestage,hs_lead_status,jobtitle,industry,annualrevenue,createdate' }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ 'Bearer ' + $json.hubspot_token }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "cd18bffb-cce6-4168-a8eb-477a0db98095",
      "name": "Map to Klaviyo List",
      "type": "n8n-nodes-base.code",
      "position": [
        1328,
        272
      ],
      "parameters": {
        "jsCode": "const cfg       = $('Configure Mapping and Settings').first().json;\nconst hsContact = $input.first().json;\nconst props     = hsContact.properties || {};\n\nconst stage     = (props.lifecyclestage || 'default').toLowerCase().replace(/[^a-z]/g,'');\nconst listId    = cfg.list_map[stage] || cfg.list_map['default'];\nconst listName  = stage.charAt(0).toUpperCase() + stage.slice(1);\n\nreturn [{ json: {\n  klaviyo_key:   cfg.klaviyo_key,\n  klaviyo_list:  listId,\n  list_name:     listName,\n  hubspot_id:    hsContact.id,\n  email:         props.email        || '',\n  first_name:    props.firstname    || '',\n  last_name:     props.lastname     || '',\n  company:       props.company      || '',\n  phone:         props.phone        || '',\n  job_title:     props.jobtitle     || '',\n  industry:      props.industry     || '',\n  annual_revenue:props.annualrevenue|| '',\n  lifecycle_stage: listName,\n  timestamp:     cfg.timestamp\n}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "1a531dad-a8f0-4cd6-a037-446ef36b4392",
      "name": "Create Klaviyo Profile",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1584,
        272
      ],
      "parameters": {
        "url": "https://a.klaviyo.com/api/profiles/",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {}
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ 'Klaviyo-API-Key ' + $json.klaviyo_key }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "revision",
              "value": "2024-02-15"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "0a5a7463-0a7b-433d-8041-2fd31cef9aa9",
      "name": "Add to Klaviyo List",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1824,
        272
      ],
      "parameters": {
        "url": "={{ 'https://a.klaviyo.com/api/lists/' + $('Map to Klaviyo List').item.json.klaviyo_list + '/relationships/profiles/' }}",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {}
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ 'Klaviyo-API-Key ' + $('Map to Klaviyo List').item.json.klaviyo_key }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "revision",
              "value": "2024-02-15"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "d6d86c1c-177a-43e8-9479-40a82e2d9605",
      "name": "Notify Sync Complete",
      "type": "n8n-nodes-base.slack",
      "position": [
        2112,
        160
      ],
      "parameters": {
        "text": "HubSpot contact synced to Klaviyo\n\nName: {{ $('Map to Klaviyo List').item.json.first_name }} {{ $('Map to Klaviyo List').item.json.last_name }}\nEmail: {{ $('Map to Klaviyo List').item.json.email }}\nCompany: {{ $('Map to Klaviyo List').item.json.company }}\nHubSpot stage: {{ $('Map to Klaviyo List').item.json.lifecycle_stage }}\nKlaviyo list: {{ $('Map to Klaviyo List').item.json.list_name }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "#crm-sync"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.2
    },
    {
      "id": "e04b57b1-e44a-447a-82c7-9e08d4bfc74d",
      "name": "Log Sync to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2112,
        384
      ],
      "parameters": {
        "columns": {
          "value": {
            "Name": "={{ $('Map to Klaviyo List').item.json.first_name + ' ' + $('Map to Klaviyo List').item.json.last_name }}",
            "Email": "={{ $('Map to Klaviyo List').item.json.email }}",
            "Status": "Synced",
            "Company": "={{ $('Map to Klaviyo List').item.json.company }}",
            "Timestamp": "={{ $('Map to Klaviyo List').item.json.timestamp }}",
            "Klaviyo List": "={{ $('Map to Klaviyo List').item.json.list_name }}",
            "HubSpot Stage": "={{ $('Map to Klaviyo List').item.json.lifecycle_stage }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Klaviyo Sync Log"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.5
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "5f64bdb9-48af-46ea-84b0-76dad56d73c3",
  "connections": {
    "Add to Klaviyo List": {
      "main": [
        [
          {
            "node": "Notify Sync Complete",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log Sync to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map to Klaviyo List": {
      "main": [
        [
          {
            "node": "Create Klaviyo Profile",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Klaviyo Profile": {
      "main": [
        [
          {
            "node": "Add to Klaviyo List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive HubSpot Contact": {
      "main": [
        [
          {
            "node": "Configure Mapping and Settings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Full HubSpot Contact": {
      "main": [
        [
          {
            "node": "Map to Klaviyo List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Configure Mapping and Settings": {
      "main": [
        [
          {
            "node": "Fetch Full HubSpot Contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

This workflow receives new HubSpot contact webhooks, fetches full contact details, maps lifecycle stages to Klaviyo lists, creates/updates the Klaviyo profile, adds it to the right list, then notifies Slack and logs the sync to Google Sheets. Receives a webhook request from…

Source: https://n8n.io/workflows/15940/ — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

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

Slack & Telegram

This workflow is a complete, production-ready solution for recovering abandoned carts in Shopify stores using a multi-channel, multi-touch approach. It automates personalized follow-ups via Email, SMS

HTTP Request, Shopify, SendGrid +5
Slack & Telegram

Turn every sales meeting into a coaching opportunity. This workflow automatically analyzes tldv meeting recordings using OpenAI (GPT-4) to provide instant, actionable feedback to your sales team.

HTTP Request, Slack, Google Sheets
Slack & Telegram

Automated video processing system that monitors S3 for new uploads, generates thumbnails and preview clips, extracts metadata, transcodes to multiple formats, and distributes to CDN with webhook notif

HTTP Request, Google Sheets, Slack
Slack & Telegram

Eliminate manual data entry from your accounts payable process. This workflow transforms raw invoice scans into structured financial records by combining UploadToURL for hosting, AWS Textract for OCR

N8N Nodes Uploadtourl, HTTP Request, Google Sheets +1
Slack & Telegram

Connect Fireflies and WayinVideo to this workflow once and every recorded sales call automatically generates a set of training clips delivered to your Slack channel. The moment Fireflies finishes tran

HTTP Request, Google Sheets, Slack