Trust & Safety — Dating and Discovery

Phishing Detection for Dating Apps & Social Discovery Platforms

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.

200,000+DNS-verified live phishing domains
04:30 UTCWhen the daily rebuild lands
100Domains per batch request
0.98Confidence returned on a hit

Screen before delivery

Extract the host from any link in a first message and check it server-side before the recipient's device ever renders the bubble.

Screen profile fields at save

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.

Feed a score, not a verdict

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.

Home / Use Cases / Dating Apps & Social Discovery
The shape of the risk

Fast intimacy between strangers is the feature and the exposure

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.

01

There is no default suspicion to fall back on

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.

02

The hand-off off-platform closes your observation window

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.

03

The emotional register works against the victim

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 is

The 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.

Campaign shapes

Six funnels that reliably end on a lookalike domain

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.

Why spam rules miss this

Inherited heuristics fire on none of the actual harm

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.

What to use instead

Position in the thread tells you where to spend

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.

"Verify before we meet"

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.

Investment and crypto funnels

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.

Fake premium upgrades

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.

Account-recovery lures

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.

Sextortion payment pages

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.

Gift-card and courier pretexts

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.

Link surfaces

Enumerate every field where a hostname can reach another human

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.

Persistent profile fields

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.

Captions, images and voice notes

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.

Invites that move the conversation elsewhere

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.

Internal fields your own staff read

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.

The inventory, field by field

  • Profile biography, tagline, and any free-text prompt answers
  • Dedicated website, link-in-bio and external-handle fields
  • First messages, ongoing chat, and message requests that were never accepted
  • Image and video captions, plus any text extracted from images
  • Voice-note transcripts, where you already generate them
  • Group, event and community descriptions on discovery-style products
  • Report narratives, appeal forms and support-ticket bodies read by staff
Honest limits

A known-bad lookup answers one question extremely well

Being precise about what the response means is what keeps the integration useful two years from now, when someone else owns it.

What the response actually asserts

A per-domain verdict over a DNS-verified live database

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.

Never render a clean result as a safety certificate

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.

It is not a replacement model

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.

Account age is not domain age

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.

Decide the unknown case in advance

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.

Read the verdict precisely
  • A hit means "known and live", not "recently seen once"
  • A miss means "not catalogued", never "verified safe"
  • Verdicts are per-domain, so one bad path does not condemn a whole host, and one clean path does not clear it
  • The open /api/v1/stats endpoint reports database size and last update, needs no key and consumes no credits, which makes it a convenient freshness probe
Integration

Five places the check earns its keep, in the order you should build them

Sequencing matters more than coverage. Ship the surface with the shortest path to harm first, then widen.

01
Ship first

Start with first messages

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.

02
Cheapest win

Then profile fields at save time

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.

03
One-off sweep

Then the back catalogue

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.

04
Compose signals

Then trust-and-safety scoring

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.

05
Operational payoff

Finally, the moderator queue

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.

100
Domains per batch call
10/s
Requests per API key
24h
Database refresh cycle
12mo
Credit validity window
Moderation criteria

Six criteria for turning a verdict into an action

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.

01

Repetition across recipients

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.

Decisive
02

Position in the conversation

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.

Heavy
03

Framing of the link

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.

Moderate
04

Account tenure, read carefully

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.

Moderate
05

Corroborating reports

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.

Heavy
06

Rotation behaviour

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.

Decisive
User-facing copy

Write the warning so the person reading it does not feel stupid

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.

Rule one — tone

Blame the sender and the site, never the reader

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.

Rule two — specificity

Say exactly what you know, and nothing you do not

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.

Rule three — next action

End on a one-tap report, not a dead end

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.

Rule four — post-click

Write a second version for the person who clicked

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.

Avoid
"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.

Prefer
"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.

Cost model

What screening actually costs at consumer volume

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.

The billing unit

One credit, one domain lookup, billed monthly

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.

Credit packages at a glance
PackagePriceCreditsPer lookup
Starter$5910,000$0.0040
Growth$9925,000$0.0040
Professional$249100,000$0.0025
Business$499250,000$0.0020
Enterprise$999750,000$0.0013

Distinct hostnames, not messages, drive the bill

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.

Worked example: a million messages a day

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.

Where the daily feed becomes the cheaper architecture

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.

Questions we get asked

Practical questions from trust-and-safety teams

Answers to the things that come up in the first design review, rather than the marketing version.

Should we block the message, or deliver it with a warning?

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.

Does a positive result justify banning the account outright?

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.

Our messaging path is latency-sensitive. Can we afford a synchronous lookup?

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.

What do we do about shortened links and redirects?

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.

How do we handle a member who says we blocked something legitimate?

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.

Can we run this against historical data without rewriting our pipeline?

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.

Where does this sit relative to the rest of our safety stack?

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.

Put a verdict where your moderators currently have a guess

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.