Skip to content

IP Blocking

Admins can block IP addresses so that leads and submissions from those IPs are clearly marked in the dashboard and can be filtered or handled differently. Blocked IPs are stored in the BlockedIPs table; honeypot (bot) leads are blocked automatically.

An IP cannot be both whitelisted and blocked. If you try to block an IP that is on the whitelist (or whitelist an IP that is blocked), the API returns an error and you must remove it from the other list first. See IP Whitelisting.

At capture: When a submission is received at /lead.capture, the request IP is checked against BlockedIPs first. If the IP is blocked, the lead is not inserted into Leads or LeadSubmissions and is not sent to Make.com. The submission is recorded in the BlockedIPLeads table for visibility, and the client receives a normal success response.

Where IP is shown

  • Leads list — Table and kanban show the lead’s contact_ip. Rows/cards whose IP is blocked use red border and light red background, plus an “IP blocked” or “Blocked” indicator.
  • Lead detail — The primary lead card shows IP address; when blocked, the card has red border/background and an “IP blocked” badge; “Block IP” is replaced by a “Blocked” badge.
  • Submission cards (lead detail) — Each submission shows its IP and blocked state (red styling and “IP blocked” badge when that submission’s IP is blocked).
  • Side panel (leads page) — When a lead is opened, the summary and each submission row show IP and blocked status; “Block IP” is available for unblocked IPs.
  • Lead submissions table (analytics) — The “Lead submissions” table (Lead submission analytics) has an IP column and shows a “Blocked” pill in the Type column when that submission’s IP is blocked.

Blocked IPs dashboard section

At Dashboard → Blocked IPs (/blocked-ips):

  • List — All blocked IPs with reason, country, referer, and blocked-at. Optional filter by IP.
  • Block an IP — Form to add a new blocked IP with optional reason, country, and referer.
  • Unblock — Remove an IP from the block list.

At Dashboard → Blocked IP leads (/blocked-ip-leads):

  • Rejected submissions — Table of leads that were rejected at /lead.capture because the IP was in the block list. Columns: Received at, IP, Contact, Email, Phone, Project, Source, Referer. Filter by IP and paginate. Use row checkboxes and Remove selected to hide chosen submissions from the listing (soft delete: rows are marked in the DB and retained for later analysis).

API

All blocked-IP endpoints require the analytics API key. See Analytics API – Blocked IPs.

MethodEndpointDescription
GET/analytics/blocked-ipsList blocked IPs (optional ?ip=, ?limit, ?offset; returns blocked_ips and total)
POST/analytics/blocked-ipsBlock an IP (body: ip, optional reason, country, referer)
DELETE/analytics/blocked-ips/:ipUnblock an IP (IP URL-encoded in path)
GET/analytics/blocked-ip-leadsList leads rejected at capture (optional ?limit, ?offset, ?ip=, ?period= quick range)
POST/analytics/blocked-ip-leads/bulk-deleteSoft-delete selected records by id (body: { "ids": [ number, ... ] }, max 100); rows hidden from list but kept in DB

Leads and submissions list/detail responses include contact_ip and is_ip_blocked (1 when that lead’s or submission’s IP is in BlockedIPs).

Honeypot auto-block

When a honeypot (bot) lead is detected, the lead’s IP is blocked automatically with reason "Honeypot". Country and referer are stored when available. No separate action is required.

Database

  • Migration 024 — Creates BlockedIPs with Ip (primary key), BlockedAt, Reason.
  • Migration 025 — Adds Country and Referer to BlockedIPs.
  • Migration 026 — Creates BlockedIPLeads for submissions rejected at capture (Ip, ReceivedAt, ContactEmail, ContactName, ContactPhone, ProjectName, Source, Referer, PayloadJson, SiteKey, FormId).
  • Migration 031 — Adds DeletedAt (TEXT, NULL) to BlockedIPLeads and TestingLeads for soft delete; rows with DeletedAt set are excluded from list views but kept for analysis.

Apply with scripts/apply-local-migrations.sh or scripts/apply-production-migrations.sh.

Primary lead card blocked state

The lead-detail API sets is_ip_blocked using a join with BlockedIPs. If that join is not used (e.g. in some environments), the backend performs a fallback lookup: when the lead has a non-empty contact_ip and the join did not set blocked, it runs a separate check against BlockedIPs and sets is_ip_blocked: 1 when the IP is found, so the primary lead card always shows the correct blocked status after a refresh.