Matchmaking products ask two strangers to build confidence in each other within a few dozen messages, then hand them a text box that accepts links. That sequence is the product. It is also, almost exactly, the sequence a fraudster needs. A per-domain lookup against a live phishing database turns one of those steps into a decision you can automate.
Extract the host from any link in a first message and check it server-side before the recipient's device ever renders the bubble.
Bios, link-in-bio fields and external handles are edited far less often than they are read. Check them once, on write, not on every impression.
A confirmed phishing domain is a heavy signal for your trust model — but it is one input among many, and it belongs in a queue rather than a silent ban.
Every other consumer product tells users to be wary of people they have never met. A discovery platform is contractually obliged to introduce them.
Most abuse-prevention writing assumes a defender's advantage that dating products simply do not have. An email gateway can lean on the fact that a message from an unknown sender is inherently suspicious. A workplace collaboration tool can lean on directory membership. A marketplace can lean on transaction history. A matchmaking platform has none of that: the entire value proposition is that the person on the other side is new, unverified by anyone in your social graph, and interesting precisely because they are unfamiliar. Suspicion is not a default state you can fall back on. It is friction you are actively paid to remove.
That inversion changes which controls are available. You cannot warn a user that "this person is not in your contacts" — nobody is. You cannot rely on reputation accumulated over months, because a healthy platform is full of people who joined last week and are behaving perfectly normally. What you can do is look at the artefacts that pass between two accounts and ask whether any of them are already known to be part of an active fraud campaign. Text is ambiguous. A hostname is not. It either appears in a database of currently-resolving phishing domains or it does not.
The second structural exposure is the deliberate hand-off. Nearly every product in this space nudges conversations towards richer channels — a video call, a phone number, an off-platform messenger — because those signals correlate with real relationships forming. Fraudsters use exactly the same nudge for the opposite reason: once the conversation leaves your surface, your logging stops, your rate limits stop, and your moderation stops. The window in which you can observe an attacker is therefore short and front-loaded. It is usually measured in the first handful of messages, and it is very often the message that contains a link.
Third, the emotional register works against the victim. A person who has spent three weeks talking to someone every morning is not evaluating a URL the way they would evaluate an unexpected invoice. They are evaluating a relationship. When the match asks them to complete a "safety verification" on an outside site before agreeing to meet, the request lands as consideration rather than as a red flag. Anyone who has read enough abuse reports knows that the most damaging campaigns are not technically sophisticated at all. They are patient, and they arrive attached to something the target wants to be true.
None of this makes the problem unsolvable. It does mean that the countermeasures which work here are the ones that operate on the mechanical layer rather than the persuasive one. You are not going to out-argue a script that has been refined across thousands of conversations. You can, however, notice that the domain it eventually asks the user to visit was catalogued as a live phishing host during last night's build, and you can act on that before the message is delivered.
Where the defensible ground isThe awkward part: the conversational signals that make a scammer detectable are the same signals that make an enthusiastic, genuinely interested new user detectable. The link they send is the one artefact where the two populations stop looking alike.
These are not separate threat actors so much as separate scripts. They differ in the pretext and converge on the same technical outcome: a page on a domain the platform has never seen before.
It is worth cataloguing these explicitly, because trust-and-safety teams tend to inherit a rule set written for spam and then discover it fires on none of the actual harm. Spam heuristics look for volume, repetition and low-effort profiles. The funnels below are typically low-volume, highly personalised and backed by profiles that look better than average. What they share is a moment where the conversation stops being a conversation and becomes an instruction to visit somewhere.
Each one also has a characteristic position in the conversation. Verification scams appear early, usually before any meeting is arranged. Investment funnels appear late, after weeks of rapport. Premium-upgrade lures appear at the moment a user hits a paywall. Knowing the position matters because it tells you where in your message pipeline the screening budget is best spent.
The match insists on a safety check through a third-party site before agreeing to a date. The page asks for a card "for age verification only" and harvests it, or captures a login the victim reuses everywhere.
Weeks of ordinary conversation followed by a casual mention of a trading portal that has been very good to them. The portal is a fabricated front end that shows fake gains until a withdrawal is attempted.
Pages that imitate your own upgrade or "unlock messages" flow, complete with your brand, hosted on a domain that resembles yours. The victim believes they are paying you.
Aimed at users who have just been locked out or suspended and are searching for help. A recovery page that captures the credential completes the takeover the attacker started.
After coercing intimate material, the follow-up is a demand with a link to a payment portal. The threat is the pressure; the domain is the part you can actually inspect.
A stranded traveller, a delayed parcel, a customs fee. Each ends on a payment or credential page whose host is frequently reused across many simultaneous conversations.
Teams usually protect chat and forget the rest. The inventory below is the first thing to write down, because anything not on it is unscreened by definition.
The obvious surface is the message body, and it is the one every integration starts with. The less obvious ones tend to be the ones that carry a link for months. A profile biography is written once and then displayed to thousands of people; if it contains a shortened link that resolves to a credential-harvesting page, the cost of missing it is not one victim but the entire audience the account is served to. The same applies to any "my links" field, external handle field, or website slot your onboarding offers.
Image captions deserve their own line in the inventory because they are frequently handled by a different service than text messages. So do photos containing text: a bio picture that is mostly a hand-written domain on a piece of card is a real pattern, and while a per-domain API cannot read it, your own optical text extraction can, and whatever it extracts can be fed into the same check. Voice notes are the newest version of the same problem — if you transcribe them for accessibility or search, the transcript is a text surface and should be treated as one.
Then there is the deliberate hand-off. Users are routinely told to continue on another messenger, and the instruction usually includes something checkable: an invite link, a channel URL, a QR code. It is worth resisting the temptation to treat these as out of scope simply because the destination is a legitimate messaging service. The invite itself is often hosted on a throwaway domain that redirects, and even where it is not, the same account frequently posts a second link later that is unambiguously malicious. Our companion notes on phishing detection for messaging apps cover the downstream half of that journey.
Finally, do not forget the fields that are technically internal. Report free-text, support tickets, appeal forms and profile-verification submissions all accept user-supplied strings, and all of them are read by a human employee whose account has considerably more privilege than a member's. Screening those is cheap and occasionally catches an attack aimed at your own staff rather than your users.
Being precise about what the response means is what keeps the integration useful two years from now, when someone else owns it.
The service behind this page is a REST API and a downloadable feed over a continuously maintained database of DNS-verified, actively resolving phishing domains. A call to /api/v1/check returns is_phishing, a category of phishing/malware, a dns_status of resolves, a last_checked date and a confidence value of 0.98 on a confirmed hit. That is a specific claim: this hostname is in a curated set of domains that are currently live and currently being used for phishing. It is not a page classifier, it does not render the destination, and it forms no opinion about a domain it has never catalogued.
The practical consequence is the one worth writing into your own documentation in bold: a clean result is not a safety certificate. is_phishing: false with a confidence of 0.0 means "no match in the database", which covers both genuinely benign sites and brand-new attacker infrastructure registered an hour ago. If your product surfaces a green tick to users on the strength of a clean lookup, you have converted a useful negative signal into a false assurance, and you will eventually own the consequences of that. Use the check to suppress the confirmed bad. Use your own behavioural signals for everything else.
This also settles an argument that comes up in every design review: whether the API can replace an in-house model. It cannot, and it is not trying to. The right mental model is a deny-list with unusually good hygiene. Every entry is verified via rotating proxy infrastructure and only domains with an active A record are included, so parked and dead entries drop out rather than accumulating. The database sits above 200,000 active domains and the daily rebuild lands at 04:30 UTC. Pair that with your own velocity, device, payment and content signals, and each covers the other's blind spot.
One more nuance specific to this vertical: account age and domain age are different measurements and neither is a proxy for the other. A three-year-old member account can be sold, stolen or simply repurposed, and a fraud ring will happily pay for aged accounts precisely because platforms weight tenure so heavily. Conversely, a brand-new account posting a domain that has been catalogued for weeks is not a coincidence — it is a rotation. Treat the domain verdict as evidence about the link, and account tenure as evidence about the actor, and resist the urge to average them into a single number that means nothing.
Finally, be honest about the unknown-domain case in your runbook rather than in the incident review. The majority of hostnames your users share will not be in any threat database, because most of the web is neither famous nor malicious. Deciding in advance what happens to that middle band — nothing, a soft interstitial, a delay for sampling, a queue entry when other signals coincide — is the difference between a system your moderators trust and one they route around.
/api/v1/stats endpoint reports database size and last update, needs no key and consumes no credits, which makes it a convenient freshness probeSequencing matters more than coverage. Ship the surface with the shortest path to harm first, then widen.
The message that opens a conversation is where the highest-value screening happens, because it is both the highest-risk artefact and the lowest-volume one. Extract every hostname from the body server-side, hold the delivery for the duration of the lookup, and only then write the message to the recipient's inbox. The single-check endpoint strips protocol prefixes and path segments for you, so passing a raw URL is acceptable, though normalising to a bare host yourself makes your cache keys cleaner. Keep the API key on the server; it is the username you chose at registration and it must never appear in a mobile bundle.
This is the cheapest integration in the whole product, because bios change rarely and reads outnumber writes by orders of magnitude. Check on write, store the verdict and the last_checked date alongside the field, and re-check on a schedule rather than on display. A weekly sweep of active profiles costs almost nothing and catches the case where a domain was clean when the bio was written and was catalogued three days later.
Every platform reaches a point where it migrates a profile table, acquires a smaller product, or simply realises that six years of stored links have never been examined. That is a batch job, not a stream: POST /api/v1/batch accepts up to 100 domains per request and bills one credit per domain, and the response gives you results[], checked, phishing_found and credits_used so reconciliation is trivial. Deduplicate hostnames before you send them — a back catalogue of two million links is usually a few tens of thousands of distinct hosts, and paying for the duplicates is pure waste. Respect the 10 requests per second per key limit and treat a 429 as backpressure rather than an error.
Feed the verdict into the model you already run rather than bolting on a parallel enforcement path. A confirmed hit is a strong feature, and it composes well with the ones you already have: how many distinct recipients received the same host, how quickly after registration the link appeared, whether the sending account has ever completed a profile photo review. The point of composition is that the phishing verdict carries the specificity while your own signals carry the context.
Add a verdict field to every report and every automated flag, showing the domain, the boolean, the category, the DNS status and the last-checked date. Moderators making dozens of decisions an hour do not have time to open a suspicious link, and they absolutely should not be doing so on a work machine. Putting the answer in the queue removes a genuinely dangerous habit from your operations. For teams already routing this into a detection pipeline, the same records flow naturally into SIEM integration and incident response workflows.
A domain hit is an input to a decision, not the decision. These are the questions that separate a considered enforcement from an automated apology.
The failure mode worth designing against is the one where a technically correct signal produces an operationally wrong outcome. A member forwards a warning about a scam site to a friend, quoting the URL. A journalist researching romance fraud pastes an example into a support ticket. A user copies a link from an email they received elsewhere and asks whether it looks safe. All three produce a positive lookup and none of them is an attacker. The weighting below is how experienced moderation teams keep the signal without the collateral damage.
One flagged link sent to one person is ambiguous. The same host sent to forty different accounts inside an hour is a campaign, and it is the single most decisive input you have.
A link in the first three messages from a brand-new account behaves very differently from a link exchanged after two months of daily conversation. Record the message index, not just the timestamp.
Was the domain presented as a destination the recipient should visit, or quoted as something to avoid? Simple contextual cues around the URL separate warning from lure.
Tenure is useful and routinely gamed. Weight it, but never let a long-lived account bypass screening — aged accounts are bought precisely because platforms trust them.
A phishing verdict that coincides with independent user reports about the same account converts a probabilistic case into an evidenced one. Join them before you act.
Posting three catalogued domains in a week, each replacing the last, is the fingerprint of infrastructure churn. Repetition of known-bad hosts is the strongest evidence in an enforcement file.
The interstitial is the only part of this system your members will ever see. It is worth the same care you would give a payment screen.
There is a strong pull towards writing security copy in the register of a reprimand, and it consistently backfires here. Someone who has been talking to a person for weeks and is about to click a link is emotionally invested. Copy that implies they have been foolish invites them to disprove it, and the easiest way to disprove it is to click anyway. Copy that puts the blame squarely on the sender and the site, and treats the reader as the person being targeted rather than the person at fault, gets far better compliance for the same number of words.
Be concrete about what you actually know, because vagueness reads as guesswork. You know the hostname. You know it appears in a maintained database of live phishing domains. You know the date it was last verified. Saying that is more persuasive than an unexplained red triangle, and it also happens to be true, which matters when a member appeals. Avoid implying certainty about the sender's intent — the account may itself have been compromised, and a warning that accuses the wrong party ages badly.
Offer a next action that is not simply "go back". People who see these warnings usually want to do something: report the account, block it, read about how the scam works, or check whether they have already given something away. A warning with a single dead-end button teaches users that warnings are obstacles. A warning that ends with a one-tap report is a warning that generates the evidence your moderation queue needs, which is a rare case of the safest option also being the operationally useful one.
Finally, write a second version of the copy for the person who has already clicked. Post-click messaging is where shame does the most damage and where speed matters most, because credential reuse means the same password may be protecting a mailbox and a bank. Keep it short, keep it practical, and link to your own account-security flow rather than a general advice page. Teams building this out often borrow structure from security-awareness material and from brand-protection playbooks, since both already assume a non-technical reader.
"Warning: you were about to fall for a scam. Never click links from people you don't know."
Assigns blame to the reader, assumes a level of naivety, and offers nothing to do next. It also assumes the sender is a stranger, which is often no longer true by the time the link arrives.
"We blocked this link. The site it points to is on a list of pages currently being used to steal logins and card details. This happens to a lot of people — here's how to report the account."
States what was found, why it matters, normalises the situation without minimising it, and ends on an action that also produces evidence for your moderation team.
The arithmetic is simple enough to do on a whiteboard, and the answer is usually smaller than teams expect because deduplication does most of the work.
Pricing is monthly subscription credits, one credit per domain lookup, billed monthly. The published packages run from Growth at $99/month for 25,000 lookups through Growth at $99/month for 25,000 lookups, Professional at $249/month for 100,000 lookups, Business at $499/month for 250,000 lookups, Enterprise at $999/month for 750,000 lookups, Enterprise at $999/month for 750,000 lookups, and Enterprise at $999/month for 750,000 lookups — which works out to $0.0008 per lookup at the top tier. Batch calls bill per domain, not per request, so batching is a latency and throughput optimisation rather than a discount.
| Package | Price | Credits | Per lookup |
|---|---|---|---|
| Starter | $59 | 10,000 | $0.0040 |
| Growth | $99 | 25,000 | $0.0040 |
| Professional | $249 | 100,000 | $0.0025 |
| Business | $499 | 250,000 | $0.0020 |
| Enterprise | $999 | 750,000 | $0.0013 |
The number that determines your bill is not messages sent, it is distinct hostnames seen. On a conversational product the overlap is enormous: a single popular link-shortener host, your own domain, a handful of major social networks and streaming services will account for a large share of all links posted, and those need to be looked up once and cached, not once per message. A cache keyed on hostname with a time-to-live tied to the daily 04:30 UTC rebuild is the single highest-leverage thing you can build, and it typically reduces billable lookups by an order of magnitude or more.
Work an example. Suppose your product carries a million messages a day and roughly three percent contain a link, giving 30,000 links. Deduplicate to distinct hosts and you might see a few thousand unique domains, of which a large fraction repeat daily and sit in cache. If you end up issuing 4,000 fresh lookups a day, that is about 120,000 a month — comfortably inside the Business package at Business at $499/month for 250,000 lookups, or the Professional package plus headroom. Add a one-off back-catalogue sweep of 80,000 distinct historical hosts and you have a predictable, bounded cost that fits a normal budget line.
Past a certain scale the sums flip and a feed subscription becomes the cheaper architecture. The Daily Threat Feed is $499 per month, delivers the full database as CSV or JSON with columns for domain, category and DNS status, and includes a daily changelog of additions and removals. The annual plan also bundles 100,000 API credits, a historical archive, priority support, custom format options and a dedicated account manager. If you are prepared to hold the list locally and join against it in memory, your marginal cost per lookup drops to zero and your latency drops to a hash lookup — see the daily feed page for the delivery formats, or compare against the monthly plans if your volume is still growing.
The hybrid most teams land on: a reasonable hybrid, and the one most mature integrations converge on: hold the feed locally for the hot path so that message delivery never waits on a network call, and keep a modest credit balance for the cases where you want a fresh answer — a moderator opening a specific report, an appeal review, or a domain that appeared after your last feed pull. Both paths use the same database, so the verdicts agree.
Answers to the things that come up in the first design review, rather than the marketing version.
Most teams settle on delivering the message with the link neutralised rather than dropping it silently. Dropping messages creates support load you cannot explain without revealing your detection logic, and it hides evidence from the recipient who might otherwise report the account. Rendering the message with the URL replaced by a warning chip keeps the conversation intact, keeps the report path open, and removes the click. Reserve full suppression for accounts that have already crossed an enforcement threshold on other grounds.
On its own, no. A single hit can come from a member warning a friend, a compromised account being used briefly by someone else, or a link copied from elsewhere. Repeated posting of known-phishing domains is a very different matter and is strong evidence in an enforcement file, particularly when the hosts rotate. The pattern most teams adopt is: first hit suppresses the link and raises a queue item, repeated hits across distinct domains or recipients triggers action, and the domain verdicts are attached to the case record as evidence.
For first messages, usually yes, because they are a small fraction of total volume and a short hold before delivery is imperceptible in a product where nobody is waiting for a reply within a second. For high-frequency ongoing chat, the better pattern is a local cache backed by the daily feed so the hot path never leaves your own process, with API calls reserved for cache misses and for moderator-initiated checks. Rate limiting is 10 requests per second per key, so a synchronous design at consumer scale needs the cache regardless.
Resolve them yourself before you check. The API answers questions about the domain you give it, so handing it a shortener host tells you only about the shortener. Follow the redirect chain server-side with a hop limit and a timeout, then check the final host — and ideally every intermediate host too, since attackers frequently chain through a disposable domain before landing. Keep the resolution off any machine that matters and never render the destination.
Give your support team the raw response rather than a summary. The last_checked date and the dns_status field together tell you whether the entry is current, and because only domains with an active A record are included, stale entries drop out of the database rather than lingering. Log every verdict you act on with a timestamp so an appeal can be answered with what was true at the time, not what is true today. If a domain is genuinely misclassified, the appeal record is what lets you find it.
Yes, and it is the usual first project. Extract distinct hostnames from your stored links, chunk them into groups of 100, and post them to the batch endpoint with your key in the request body. The response includes the per-domain results plus counts of how many were checked, how many were phishing and how many credits were used, which makes it easy to reconcile against your billing expectations. A back-catalogue sweep after a database migration is a one-off cost, not a recurring one.
Think of it as one high-precision detector among several. It will not catch a scam that never includes a link, it will not read an image, and it will not judge a domain nobody has catalogued yet. What it does is remove an entire class of confirmed harm cheaply and without human review, which frees your moderators to spend their attention on the ambiguous cases where judgement actually helps. Teams running adjacent products often deploy the same database in DNS filtering or email security as well.
Pick a monthly plan, run a batch of your stored profile links through the check endpoint, and see how much of your existing report backlog resolves to domains that were already known. It is a short experiment with an unambiguous result, and a Starter package covers it several times over.