← Blog
phishingdomain-securitytutorialapi

How to Detect Phishing Domains Programmatically

A practical guide to scoring domains for typosquatting, combo-squatting, newly registered flags, and infrastructure anomalies — with code examples.

Entropy0 Team··5 min read

Phishing domains share a handful of fingerprints. They are typically registered within days of a campaign, mimic a brand name through typos or keyword injection, use free DV certificates, and host on shared infrastructure that is hard to trace back.

Checking these signals manually does not scale. This post walks through how to evaluate a domain programmatically — from the signals to look for, to an API call that returns a structured verdict you can act on in code.

The Signals That Matter

A domain can look totally legitimate at first glance — valid SSL, real DNS records, an accessible website. Phishing domains are built to pass those surface checks. The real signal is in the combination of factors:

| Signal | What it tells you | |--------|-------------------| | Domain age | < 30 days is a major red flag for brand-targeted campaigns | | Typo distance | Levenshtein distance ≤ 2 from a known brand (e.g. g00gle.com) | | Keyword injection | Brand name embedded before or after a generic word (paypal-secure.com) | | TLD swap | Identical base domain, non-standard TLD (stripe.net, stripe.xyz) | | Certificate issuer | Free DV cert from Let's Encrypt on a "banking" domain is suspicious | | WHOIS privacy | Redacted registrant on a domain that claims to be a financial institution | | Missing email hygiene | No SPF, DMARC, or MX records — domain isn't set up to send real email |

No single signal is conclusive. The combination is what matters.

Checking Manually vs. Programmatically

Here is what a manual WHOIS + DNS check looks like:

whois g00gle-login.com | grep -E "Creation|Registrar|Registrant"
dig g00gle-login.com TXT | grep spf

This works for spot-checking one domain. At any scale — monitoring a watchlist, validating user-submitted URLs, screening links in a RAG pipeline — you need a structured API response you can branch on.

Using the Entropy0 API

The /api/v1/clarity endpoint runs DNS, WHOIS, SSL, and content analysis in a single call and returns a scored verdict.

curl -X POST https://entropy0.ai/api/v1/clarity \
  -H "Authorization: Bearer sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input": "g00gle-login.com"}'

The response includes three independent scores:

{
  "trustScore": 12,
  "scoreDetails": {
    "threatScore": 74,
    "threatLevel": "high",
    "deviationFinal": 82,
    "lookalike": {
      "detected": true,
      "kind": "typosquat",
      "note": "Levenshtein distance 2 from google.com"
    },
    "domainState": { "state": "active" },
    "threatReasons": [
      "Typosquatting detected: high similarity to google.com",
      "Domain registered 4 days ago",
      "Free DV certificate from Let's Encrypt",
      "No SPF or DMARC records"
    ]
  }
}

A threatScore above 50 with lookalike.detected = true is a hard signal. A newly registered domain with no email hygiene on top of that makes it a deny in any reasonable policy.

Branching on the Result

Here is a minimal Node.js example that checks a domain and returns an action:

async function evaluateDomain(domain: string): Promise<"allow" | "warn" | "deny"> {
  const res = await fetch("https://entropy0.ai/api/v1/clarity", {
    method:  "POST",
    headers: {
      "Authorization":  `Bearer ${process.env.ENTROPY0_API_KEY}`,
      "Content-Type":   "application/json",
    },
    body: JSON.stringify({ input: domain }),
  });

  const data = await res.json();
  const sd   = data.scoreDetails ?? {};

  if (sd.threatScore >= 60 || sd.lookalike?.detected) return "deny";
  if (sd.threatScore >= 30 || sd.deviationFinal >= 50) return "warn";
  return "allow";
}

This pattern works anywhere you need a binary or ternary gate: link previews, form URL validation, agent tool calls, webhook source verification.

The /decide Endpoint for Richer Context

If you need more than a score — an explicit recommended action with reasoning — use /api/v1/decide instead:

curl -X POST https://entropy0.ai/api/v1/decide \
  -H "Authorization: Bearer sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "target": { "url": "https://g00gle-login.com/verify" },
    "context": { "kind": "navigate", "sensitivity": "high" },
    "policy":  "strict"
  }'

Response:

{
  "decision":    "deny",
  "confidence":  "high",
  "reasoning":   "Typosquat of google.com registered 4 days ago. High deviation. No email infrastructure.",
  "evidence":    ["lookalike_detected", "newly_registered", "missing_spf", "missing_dmarc"],
  "validUntil":  "2026-04-15T12:05:00Z"
}

The evidence array gives you specific reason codes you can log, display, or pass to a downstream system.

Watchlist Use Case

If you are monitoring a list of domains over time — a brand protection watchlist, a set of user-submitted links, or a daily Tranco sample — run them through the API in batch and persist the results:

const domains = ["g00gle-login.com", "paypa1.com", "stripe-verify.xyz"];

const results = await Promise.all(
  domains.map((d) => evaluateDomain(d))
);

results.forEach((verdict, i) => {
  console.log(`${domains[i]}: ${verdict}`);
});

Alert on any domain that transitions from allow to warn or deny between runs — that is how you catch a domain that was registered clean and later weaponised.

Summary

Detecting phishing domains programmatically comes down to:

  1. Layer your signals — age, lookalike, certificate, email hygiene — no single signal is enough
  2. Evaluate in context — a newly registered domain is less suspicious if it is a personal project; more suspicious if it is masquerading as a bank
  3. Act on scores, not just flags — a continuous threat score lets you tune thresholds per use case
  4. Watch for state changes — the most dangerous domains start clean and go live later

The Entropy0 API handles steps 1–3 in a single HTTP call. You handle the policy.


Get a free API key and scan your first domain in under a minute. No credit card required.

Try Entropy0 — free API key

Scan any domain and get trust, threat, and deviation scores with full signal explanations. No credit card. Takes 30 seconds.