AutomationFlowsGeneral › Monitor Brand Domains and Typosquat Variants with Domainkits and Email

Monitor Brand Domains and Typosquat Variants with Domainkits and Email

ByABTdomain @lyalphaniub on n8n.io

This workflow runs daily to monitor newly registered domains matching your brand keyword and to check typosquat variants of your brand domain using DomainKits, then compiles WHOIS/DNS details into a CSV and emails a plaintext report. Runs daily at 14:00 UTC and sets the brand…

Cron / scheduled trigger★★★★☆ complexity16 nodesN8N Nodes DomainkitsEmail Send
General Trigger: Cron / scheduled Nodes: 16 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #17669 — 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
{
  "name": "Monitor newly registered domains and typosquat variants for your brand with DomainKits",
  "nodes": [
    {
      "id": "c0000000-0000-0000-0000-000000000001",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -680,
        -260
      ],
      "parameters": {
        "width": 520,
        "height": 1140,
        "content": "## Monitor newly registered domains and typosquat variants with DomainKits\n\n### How it works\n\nEach day this workflow collects domain registration data for one domain you own, in two independent parts. Part one lists the domains registered in the last 10 days whose name contains your brand keyword, and looks up WHOIS and DNS for each: registrar, nameservers, A records and MX records. Part two generates the mechanical typosquat variants of your domain and reports which are registered, listed for sale or expiring. The workflow reports what the data says and leaves the interpretation to you.\n\n### Setup steps\n\n- Set your brand domain in the Set Brand node. Everything downstream derives from it, so this is the only value you need to edit.\n- Add your DomainKits API credentials to the four DomainKits nodes. One key covers every endpoint.\n- Configure the Send Report node with your SMTP credentials and recipients. The schedule is set to 14:00 UTC, by which time the previous day's registration data is complete.\n\n### Customization\n\nSwap the Send Report node for Slack, Jira or a ticketing system to route the report into an existing workflow. Add a Filter node after Prepare Candidates to narrow the list before the WHOIS and DNS lookups run.\n\n### Quota note\n\nEach run costs one search per section plus two lookups per candidate domain. A brand matching 30 new registrations a day uses roughly 60 lookups per run.\n\n### Data note\n\nResults contain domain names, registration dates, registrar names, nameservers and DNS records only. No registrant personal data is included (no names, emails, addresses or phone numbers), so the output is GDPR compliant and safe to forward or store."
      },
      "typeVersion": 1
    },
    {
      "id": "c0000000-0000-0000-0000-000000000002",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -40,
        -260
      ],
      "parameters": {
        "color": 7,
        "width": 1000,
        "height": 600,
        "content": "## Collect\n\nRuns daily and sets the brand domain once. Two independent lookups follow: yesterday's new registrations containing the brand keyword, and the typosquat variants of the brand domain."
      },
      "typeVersion": 1
    },
    {
      "id": "c0000000-0000-0000-0000-000000000003",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1020,
        -260
      ],
      "parameters": {
        "color": 7,
        "width": 760,
        "height": 600,
        "content": "## Look up each domain\n\nQueries WHOIS and DNS for every domain in the list and records the registrar, nameservers, A records and MX records as returned."
      },
      "typeVersion": 1
    },
    {
      "id": "c0000000-0000-0000-0000-000000000004",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1840,
        -260
      ],
      "parameters": {
        "color": 7,
        "width": 760,
        "height": 600,
        "content": "## Report and deliver\n\nLists the registrations newest first, summarises variant coverage separately, converts the records to a CSV attachment and emails both."
      },
      "typeVersion": 1
    },
    {
      "id": "c1000000-0000-0000-0000-000000000001",
      "name": "Every Day at 2pm",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        80
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "days",
              "triggerAtHour": 14
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "c1000000-0000-0000-0000-000000000002",
      "name": "Set Brand",
      "type": "n8n-nodes-base.set",
      "position": [
        240,
        80
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "d1+12345678900-+1234567890",
              "name": "brand_domain",
              "type": "string",
              "value": "domainkits.com"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "c1000000-0000-0000-0000-000000000003",
      "name": "Find New Registrations",
      "type": "n8n-nodes-domainkits.domainKits",
      "position": [
        480,
        0
      ],
      "parameters": {
        "limit": 100,
        "filters": {
          "days_range": "0-10"
        },
        "keyword": "={{ $json.brand_domain.split('.')[0] }}",
        "resource": "nrd",
        "operation": "search",
        "searchMode": "keyword"
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "c1000000-0000-0000-0000-000000000004",
      "name": "Generate Typo Variants",
      "type": "n8n-nodes-domainkits.domainKits",
      "position": [
        480,
        180
      ],
      "parameters": {
        "domain": "={{ $json.brand_domain }}",
        "resource": "lookup",
        "operation": "typosquat"
      },
      "typeVersion": 1
    },
    {
      "id": "c1000000-0000-0000-0000-000000000010",
      "name": "Wait For Both",
      "type": "n8n-nodes-base.merge",
      "position": [
        720,
        80
      ],
      "parameters": {
        "mode": "chooseBranch",
        "options": {},
        "useDataOfInput": 1
      },
      "typeVersion": 3
    },
    {
      "id": "c1000000-0000-0000-0000-000000000005",
      "name": "Prepare Candidates",
      "type": "n8n-nodes-base.code",
      "position": [
        1060,
        80
      ],
      "parameters": {
        "jsCode": "const candidates = $('Find New Registrations').all()\n  .map(i => i.json)\n  .filter(d => d.domain);\n\n// One item carrying the whole batch: the bulk lookups run once for the list\n// instead of once per domain. The API caps a batch at 30 domains.\nreturn [{\n  json: {\n    domains: candidates.map(d => d.domain).slice(0, 30),\n    candidates,\n  },\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "c1000000-0000-0000-0000-000000000006",
      "name": "Bulk WHOIS",
      "type": "n8n-nodes-domainkits.domainKits",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        1300,
        80
      ],
      "parameters": {
        "domains": "={{ $json.domains }}",
        "resource": "lookup",
        "operation": "whoisBulk"
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "alwaysOutputData": true,
      "waitBetweenTries": 2000
    },
    {
      "id": "c1000000-0000-0000-0000-000000000007",
      "name": "Bulk DNS",
      "type": "n8n-nodes-domainkits.domainKits",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        1540,
        80
      ],
      "parameters": {
        "domains": "={{ $('Prepare Candidates').first().json.domains.slice(0, 20) }}",
        "resource": "lookup",
        "operation": "dnsBulk"
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "alwaysOutputData": true,
      "waitBetweenTries": 2000
    },
    {
      "id": "c1000000-0000-0000-0000-000000000008",
      "name": "Build Report",
      "type": "n8n-nodes-base.code",
      "position": [
        1880,
        80
      ],
      "parameters": {
        "jsCode": "const base = $('Prepare Candidates').first().json.candidates;\n\nconst whoisByDomain = new Map();\nfor (const w of $('Bulk WHOIS').all().map(i => i.json)) {\n  if (w.domain) whoisByDomain.set(w.domain, w);\n}\nconst dnsByDomain = new Map();\nfor (const d of $('Bulk DNS').all().map(i => i.json)) {\n  if (d.domain) dnsByDomain.set(d.domain, d);\n}\n\nconst brand = $('Set Brand').first().json;\nconst keyword = brand.brand_domain.split('.')[0];\n\nconst records = base.map((b) => {\n  const w = whoisByDomain.get(b.domain) || {};\n  const dns = dnsByDomain.get(b.domain) || {};\n  return {\n    domain: b.domain,\n    registered_date: b.registered_date || '',\n    expiry_date: b.expiry_date || '',\n    registrar: w.registrar_name || '',\n    nameservers: (w.nameservers || dns.nameservers || []).filter(Boolean),\n    domain_status: dns.domain_status || '',\n  };\n});\n\nrecords.sort((a, b) => (b.registered_date || '').localeCompare(a.registered_date || '') || a.domain.localeCompare(b.domain));\n\nconst variantItems = $('Generate Typo Variants').all().map(i => i.json).filter(v => v.domain);\nconst registeredVariants = variantItems.filter(v => v.registered);\nconst generatedCount = variantItems[0]?._total ?? registeredVariants.length;\n\nconst byType = {};\nfor (const v of registeredVariants) {\n  byType[v.type] = (byType[v.type] || 0) + 1;\n}\nconst forSale = registeredVariants.filter(v => v.status === 'for_sale').map(v => v.domain);\nconst expiring = registeredVariants.filter(v => v.status === 'expiring').map(v => v.domain);\n\nconst lines = records.map(r => {\n  const parts = [\n    r.domain,\n    `  registered ${r.registered_date || 'not reported'}` + (r.expiry_date ? `, expires ${r.expiry_date}` : ''),\n    `  registrar: ${r.registrar || 'not reported'}`,\n  ];\n  parts.push(`  nameservers: ${r.nameservers.length ? r.nameservers.join(', ') : 'none'}`);\n  if (r.domain_status) parts.push(`  status: ${r.domain_status}`);\n  return parts.join('\\n');\n});\n\nconst body = [\n  `Domain data report for ${brand.brand_domain}`,\n  'Rolling window: domains registered in the last 10 days',\n  '',\n  `=== SECTION 1: Registrations containing \"${keyword}\" ===`,\n  '',\n  `${records.length} domains, newest first. Empty fields mean the lookup returned nothing.`,\n  '',\n  records.length ? lines.join('\\n\\n') : 'No registrations matched the keyword in the last 10 days.',\n  '',\n  '',\n  `=== SECTION 2: Typosquat variants of ${brand.brand_domain} ===`,\n  '',\n  'Mechanical variants generated from your domain. Independent of section 1: these come from your domain, not from recent registrations.',\n  '',\n  `${registeredVariants.length} of ${generatedCount} generated variants are registered.`,\n  '',\n  'By mutation type:',\n  Object.entries(byType).sort((a, b) => b[1] - a[1]).map(([t, n]) => `  ${t}: ${n}`).join('\\n'),\n  '',\n  `Listed for sale: ${forSale.length}${forSale.length ? ' (' + forSale.slice(0, 10).join(', ') + (forSale.length > 10 ? ', ...' : '') + ')' : ''}`,\n  `Expiring: ${expiring.length}${expiring.length ? ' (' + expiring.slice(0, 10).join(', ') + (expiring.length > 10 ? ', ...' : '') + ')' : ''}`,\n  '',\n  'Full records are attached as CSV.',\n].join('\\n');\n\nreturn [{\n  json: {\n    subject: `${brand.brand_domain}: ${records.length} registrations in the last 10 days`,\n    message: body,\n    records,\n    variant_summary: {\n      generated: generatedCount,\n      registered: registeredVariants.length,\n      by_type: byType,\n      for_sale: forSale,\n      expiring: expiring,\n    },\n  },\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "c1000000-0000-0000-0000-000000000009",
      "name": "Send Report",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        2360,
        80
      ],
      "parameters": {
        "text": "={{ $('Build Report').first().json.message }}",
        "options": {
          "attachments": "data"
        },
        "subject": "={{ $('Build Report').first().json.subject }}",
        "toEmail": "you@example.com",
        "fromEmail": "user@example.com",
        "emailFormat": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "c1000000-0000-0000-0000-000000000012",
      "name": "Split Findings",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        2120,
        180
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "records"
      },
      "typeVersion": 1
    },
    {
      "id": "c1000000-0000-0000-0000-000000000011",
      "name": "Findings To CSV",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        2120,
        0
      ],
      "parameters": {
        "options": {},
        "operation": "csv"
      },
      "typeVersion": 1.1
    }
  ],
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Bulk DNS": {
      "main": [
        [
          {
            "node": "Build Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Brand": {
      "main": [
        [
          {
            "node": "Find New Registrations",
            "type": "main",
            "index": 0
          },
          {
            "node": "Generate Typo Variants",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Bulk WHOIS": {
      "main": [
        [
          {
            "node": "Bulk DNS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Report": {
      "main": [
        [
          {
            "node": "Split Findings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait For Both": {
      "main": [
        [
          {
            "node": "Prepare Candidates",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Findings": {
      "main": [
        [
          {
            "node": "Findings To CSV",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Findings To CSV": {
      "main": [
        [
          {
            "node": "Send Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every Day at 2pm": {
      "main": [
        [
          {
            "node": "Set Brand",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Candidates": {
      "main": [
        [
          {
            "node": "Bulk WHOIS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find New Registrations": {
      "main": [
        [
          {
            "node": "Wait For Both",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Typo Variants": {
      "main": [
        [
          {
            "node": "Wait For Both",
            "type": "main",
            "index": 1
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

This workflow runs daily to monitor newly registered domains matching your brand keyword and to check typosquat variants of your brand domain using DomainKits, then compiles WHOIS/DNS details into a CSV and emails a plaintext report. Runs daily at 14:00 UTC and sets the brand…

Source: https://n8n.io/workflows/17669/ — 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 runs every 30 minutes to monitor a keyword across DomainKits newly registered domain data and Certificate Transparency activity, correlates both feeds, and emails only what changed since

N8N Nodes Domainkits, Email Send
General

Perfect for content publishing with organic scheduling patterns, social media automation, API systems that need to avoid rate limiting, or any automation requiring randomised timing control across mul

n8n, Read Write File, Stop And Error +1
General

Complete backup solution that saves both workflows and credentials to local/server disk with optional FTP upload for off-site redundancy.

Read Write File, Email Send, Execute Command +3
General

dev_activity_reporter. Uses dataTable, emailSend. Scheduled trigger; 19 nodes.

Data Table, Email Send
General

This n8n workflow automates the secure transfer of files between FTP servers on a scheduled basis, providing enterprise-grade reliability with comprehensive error handling and dual notification system

Ftp, Email Send