AutomationFlowsGeneral › Update Klicktipp Contact Tags by Tag Names

Update Klicktipp Contact Tags by Tag Names

ByKlickTipp @KlickTipp on n8n.io

This workflow uses KlickTipp community nodes, available for self-hosted n8n instances only.

Event trigger★★★★☆ complexity18 nodesExecute Workflow TriggerN8N Nodes Klicktipp
General Trigger: Event Nodes: 18 Complexity: ★★★★☆ Added:

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

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": "u3Rrbxden8smAQrx",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "KlickTipp tag manager: update contact tags by names",
  "tags": [
    {
      "id": "15wrq9sti6wyqr6J",
      "name": "TEMPLATE",
      "createdAt": "2025-01-08T16:34:30.163Z",
      "updatedAt": "2025-01-08T16:34:30.163Z"
    }
  ],
  "nodes": [
    {
      "id": "49694fe4-0bb6-4e89-a386-a661eb7c856c",
      "name": "Input: Email + Tag names",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        -16,
        320
      ],
      "parameters": {
        "inputSource": "jsonExample",
        "jsonExample": "{\n  \"email\": \"example@email.com\",\n  \"tagNamesToAdd\": [\"Tag name 1\", \"Tag name 2\"],\n  \"tagNamesToRemove\": [\"Tag name 3\"]\n}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "cd405fb5-b0f3-4186-8da2-9ecbd7ab8b34",
      "name": "Compare desired vs current tags",
      "type": "n8n-nodes-base.code",
      "position": [
        368,
        320
      ],
      "parameters": {
        "jsCode": "// Retrieve input variables\nconst allTags = $(\"Get tag list\").all() || [];\nconst input = $('Input: Email + Tag names').first().json || {};\nconst tagNamesToAdd = Array.isArray(input.tagNamesToAdd) ? input.tagNamesToAdd : [];\nconst tagNamesToRemove = Array.isArray(input.tagNamesToRemove) ? input.tagNamesToRemove : [];\n\n// Helpers\nconst normalizeString = (s) => String(s ?? '').trim();\nconst normalizeKey = (s) => normalizeString(s).toLowerCase();;\n\n// Build lookup: tag name -> tag ID\n// allTags items expected like: { label: \"Tag name\", value: \"123\" }\nconst tagNameToId = /** @type {Record<string, number>} */ ({});\nfor (const tag of allTags) {\n  if (!tag || typeof tag.json.value !== 'string') {\n     continue;\n  }\n  const id = Number(tag.json.id);\n\n  if (Number.isNaN(id)) {\n    continue;\n  }\n  tagNameToId[normalizeKey(tag.json.value)] = id;\n}\n\n// Resolve names -> IDs (dedupe, ignore unknown)\nconst getUniqueNormalizedKeys = (arr) => [...new Set(arr.map(normalizeKey).filter(k => k !== ''))];\n\nconst addKeys = getUniqueNormalizedKeys(tagNamesToAdd);\nconst removeKeys = getUniqueNormalizedKeys(tagNamesToRemove);\n\nconst tagIdsToAdd = addKeys\n  .map(k => tagNameToId[k])\n  .filter(id => typeof id === 'number' && !Number.isNaN(id));\n\nconst tagIdsToRemove = removeKeys\n  .map(k => tagNameToId[k])\n  .filter(id => typeof id === 'number' && !Number.isNaN(id));\n\nreturn [{ tagIdsToAdd, tagIdsToRemove }];"
      },
      "typeVersion": 2
    },
    {
      "id": "e39cf9aa-d4b7-4f2e-8947-45a78da336de",
      "name": "If tags to add",
      "type": "n8n-nodes-base.filter",
      "position": [
        592,
        208
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c22b609f-a2a3-4230-ad2c-ff43565f13ff",
              "operator": {
                "type": "array",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.tagIdsToAdd }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b9412193-df1f-4731-908b-fb9d43ad14c4",
      "name": "If tags to remove",
      "type": "n8n-nodes-base.filter",
      "position": [
        592,
        432
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c22b609f-a2a3-4230-ad2c-ff43565f13ff",
              "operator": {
                "type": "array",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.tagIdsToRemove }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "0d2bdd22-08e4-4bef-be63-b09d7acd2995",
      "name": "Add tags to contact",
      "type": "n8n-nodes-klicktipp.klicktipp",
      "position": [
        784,
        208
      ],
      "parameters": {
        "email": "={{ $('Input: Email + Tag names').first().json.email }}",
        "tagId": "={{ $json.tagIdsToAdd }}",
        "resource": "contact-tagging"
      },
      "credentials": {
        "klickTippApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "8295bbc0-465d-4543-9446-6e88f5aaa5aa",
      "name": "Split tags to remove",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        784,
        432
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "tagIdsToRemove"
      },
      "typeVersion": 1
    },
    {
      "id": "ed6b2475-6ea9-4a90-ae77-dd7ab0d7f4b2",
      "name": "Remove tag from contact",
      "type": "n8n-nodes-klicktipp.klicktipp",
      "position": [
        992,
        432
      ],
      "parameters": {
        "email": "={{ $('Input: Email + Tag names').first().json.email }}",
        "tagId": "={{ $json.tagIdsToRemove }}",
        "resource": "contact-tagging",
        "operation": "untag"
      },
      "credentials": {
        "klickTippApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "44076f87-9cbc-432b-a633-6c898fcfcc92",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -80,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 224,
        "height": 496,
        "content": "## Input"
      },
      "typeVersion": 1
    },
    {
      "id": "8faa2178-729c-4405-981a-25046c538d8b",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        160,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 160,
        "height": 496,
        "content": "## Fetch tag list"
      },
      "typeVersion": 1
    },
    {
      "id": "37393001-dcbb-451c-9309-62870560b7ac",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 608,
        "height": 224,
        "content": "## Add missing tags"
      },
      "typeVersion": 1
    },
    {
      "id": "2341be14-61d8-4c2a-95cd-9bfffbd3a507",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        384
      ],
      "parameters": {
        "color": 7,
        "width": 608,
        "height": 256,
        "content": "## Remove extra tags"
      },
      "typeVersion": 1
    },
    {
      "id": "cb6590d1-22aa-41fa-98ac-f58bfb45f25a",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        336,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 368,
        "height": 496,
        "content": "## Compare tags and build actions"
      },
      "typeVersion": 1
    },
    {
      "id": "a01abb7c-12e1-4b75-a0c2-b94b9d9dd3ed",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -752,
        144
      ],
      "parameters": {
        "width": 656,
        "height": 1344,
        "content": "### Introduction\nThis workflow receives a contact email plus two arrays of tag names: one list of tags to add and one list of tags to remove. It loads the full KlickTipp tag list, resolves the provided tag names into tag IDs, and then applies the changes to the contact by tagging and untagging. It is designed to be a reusable \"Contact Tagging\" sub-workflow for any n8n automation.\n\n### Benefits\n- Applies explicit tag changes (add/remove) without requiring full tag synchronization.\n- Automatically resolves tag names to KlickTipp tag IDs.\n- Keeps parent workflows simple (no manual tag ID lookups).\n- Reusable module for consistent tagging behavior across automations.\n\n---\n\n### Key Features\n\n#### Input\nExpects the contact email plus two arrays of tag names.\n\nExample input:\n```\n{\n  \"email\": \"example@email.com\",\n  \"tagNamesToAdd\": [\"Tag name 1\", \"Tag name 2\"],\n  \"tagNamesToRemove\": [\"Tag name 3\"]\n}\n```\n\n#### Processing\n- Loads the full KlickTipp tag list.\n- Resolves tagNamesToAdd[] into tagIdsToAdd[].\n- Resolves tagNamesToRemove[] into tagIdsToRemove[].\n- If tagIdsToAdd[] is not empty, adds these tags to the contact.\n- If tagIdsToRemove[] is not empty, splits the array and removes tags from the contact one-by-one.\n\n#### Output\nThis workflow updates the contact in KlickTipp by:\n- adding all tags resolved from tagNamesToAdd[]\n- removing all tags resolved from tagNamesToRemove[]\n\n---\n\n### Testing\n- Test with a contact that already exists in KlickTipp.\n- Provide tagNamesToAdd[] containing:\n  - existing KlickTipp tags (should be added to the contact)\n  - non-existing tags (will be ignored unless you add \u201ccreate tag\u201d logic)\n- Provide tagNamesToRemove[] containing:\n  - existing KlickTipp tags (should be removed from the contact if present)\n  - non-existing tags (will be ignored)\n- Confirm in KlickTipp that:\n  - tags from tagNamesToAdd[] were added\n  - tags from tagNamesToRemove[] were removed"
      },
      "typeVersion": 1
    },
    {
      "id": "4a07b3ef-55bf-4422-86b8-49b5d7a8aebb",
      "name": "Get tag list",
      "type": "n8n-nodes-klicktipp.klicktipp",
      "position": [
        192,
        320
      ],
      "parameters": {},
      "credentials": {
        "klickTippApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "14044bb4-54fc-42ae-9dd8-d7cefb3379d6",
      "name": "Return result to parent workflow",
      "type": "n8n-nodes-base.set",
      "position": [
        1616,
        304
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "66b091f0-9d62-4adf-9365-3961b0879616",
              "name": "success",
              "type": "boolean",
              "value": "={{\n  $if(\n    $(\"Collect removal results\").isExecuted,\n    (\n      Array.isArray($(\"Collect removal results\").first().json.success)\n        ? $(\"Collect removal results\").first().json.success.every(Boolean)\n        : Boolean($(\"Collect removal results\").first().json.success)\n    ),\n    true\n  )\n  &&\n  $if(\n    $(\"Add tags to contact\").isExecuted,\n    Boolean($(\"Add tags to contact\").first().json.success),\n    true\n  )\n}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "950d20e7-9950-44f1-b048-1d6f97bde0a2",
      "name": "Collect removal results",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        1184,
        432
      ],
      "parameters": {
        "options": {},
        "fieldsToAggregate": {
          "fieldToAggregate": [
            {
              "fieldToAggregate": "success"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d0cca038-e52a-44c4-b0ef-fc0d93e77a72",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1344,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 464,
        "height": 496,
        "content": "## Compute final success (add + remove)"
      },
      "typeVersion": 1
    },
    {
      "id": "e93a5a83-b597-4201-9a19-25876d907764",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        1408,
        304
      ],
      "parameters": {},
      "typeVersion": 3.2
    }
  ],
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "2efaad98-0f14-470f-ba1e-dcb95e7b4076",
  "connections": {
    "Merge": {
      "main": [
        [
          {
            "node": "Return result to parent workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get tag list": {
      "main": [
        [
          {
            "node": "Compare desired vs current tags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If tags to add": {
      "main": [
        [
          {
            "node": "Add tags to contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If tags to remove": {
      "main": [
        [
          {
            "node": "Split tags to remove",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add tags to contact": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split tags to remove": {
      "main": [
        [
          {
            "node": "Remove tag from contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Collect removal results": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Remove tag from contact": {
      "main": [
        [
          {
            "node": "Collect removal results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Input: Email + Tag names": {
      "main": [
        [
          {
            "node": "Get tag list",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compare desired vs current tags": {
      "main": [
        [
          {
            "node": "If tags to add",
            "type": "main",
            "index": 0
          },
          {
            "node": "If tags to remove",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

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.

Pro

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

About this workflow

This workflow uses KlickTipp community nodes, available for self-hosted n8n instances only.

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

More General workflows → · Browse all categories →

Related workflows

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

General

This workflow uses KlickTipp community nodes, available for self-hosted n8n instances only.

N8N Nodes Klicktipp, Execute Workflow Trigger
General

Agendamiento. Uses n8n-nodes-evolution-api, redis, dataTable, executeWorkflowTrigger. Event-driven trigger; 60 nodes.

N8N Nodes Evolution Api, Redis, Data Table +2
General

Prevent concurrent workflow runs using Redis. Uses executeWorkflowTrigger, manualTrigger, stickyNote, executeWorkflow. Event-driven trigger; 43 nodes.

Execute Workflow Trigger, Redis, Stop And Error
General

This workflow sets a small "lock" value in Redis so that only one copy of a long job can run at the same time. If another trigger fires while the job is still busy, the workflow sees the lock, stops e

Execute Workflow Trigger, Redis, Stop And Error
General

Reputation Engine — Site Refresh. Uses httpRequest, executeWorkflowTrigger. Event-driven trigger; 35 nodes.

HTTP Request, Execute Workflow Trigger