Example: Catching Romance Scams (Cross Account Duplicates)

It's common for organized catfishers, scammers, and other nefarious actors to use shared sets of assets to deceive your application's users.

How FEVER Helps

  • Your media content will have a fingerprint associated after FEVER runs.
  • FEVER automates rapid comparison of those fingerprints using the Duplicates API.
  • FEVER reports grouped clusters of assets that are a bit too similar.
  • FEVER also does automatic synthetic content scoring - it can help label suspected AI content.
  • You can use these groups to inform Trust & Safety decisions on flagged content: flag, shadow ban, manual review queue - your call.

Implementation Guide

  • If you have not already installed FEVER, follow the Quick Start Guide.
  • 1. Load the Admin console, and navigate to the Duplicates tab. FEVER automatically suggests a threshold value for "how similar is too similar".
  • 2. Experiment with the cutoff, and filter by customer ID to determine when you see the most duplicates across accounts in the Admin console.
  • 3. Any cluster spanning multiple customer_ids can be suspect - why would several accounts in several locations submit the same, or nearly the same content?
  • 4. Once you visually validate what results are caught with a given cutoff value, use the snippets below to get your app to automate taking actions.
  • Admin console Duplicates tab showing cross-account duplicate clusters
    Tune the cutoff in the Duplicates tab before automating.

Code Starters

import asyncio

import fever_client

async def main():
    config = fever_client.Configuration(
        host="https://your-appliance",
        access_token="YOUR_API_KEY",
    )
    async with fever_client.ApiClient(config) as client:
        duplicates = fever_client.DuplicatesApi(client)
        result = await duplicates.find_duplicates(
            fever_client.DuplicatesRequest(threshold=0.92)
        )
        for cluster in result.duplicate_clusters or []:
            accounts = {c for c in cluster.member_customers if c}
            if len(accounts) > 1:
                for customer_id in accounts:
                    print("flag for review:", customer_id, cluster.members)

asyncio.run(main())
import { Configuration, DuplicatesApi } from "fever-client";

const duplicates = new DuplicatesApi(
  new Configuration({
    basePath: "https://your-appliance",
    accessToken: "YOUR_API_KEY",
  })
);

const result = await duplicates.findDuplicates({
  duplicatesRequest: { threshold: 0.92 },
});
for (const cluster of result.duplicateClusters ?? []) {
  const accounts = new Set(cluster.memberCustomers?.filter(Boolean) ?? []);
  if (accounts.size > 1) {
    for (const customerId of accounts) {
      console.log("flag for review:", customerId, cluster.members);
    }
  }
}
package main

import (
	"context"
	"fmt"

	fever "github.com/Lowdown-Labs/fever-clients/clients/go"
)

func main() {
	cfg := fever.NewConfiguration()
	cfg.Servers = fever.ServerConfigurations{{URL: "https://your-appliance"}}
	ctx := context.WithValue(context.Background(), fever.ContextAccessToken, "YOUR_API_KEY")
	client := fever.NewAPIClient(cfg)

	req := fever.NewDuplicatesRequest()
	req.SetThreshold(0.92)
	result, _, err := client.DuplicatesAPI.FindDuplicates(ctx).DuplicatesRequest(*req).Execute()
	if err != nil {
		panic(err)
	}
	for _, cluster := range result.GetDuplicateClusters() {
		accounts := map[string]bool{}
		for _, c := range cluster.GetMemberCustomers() {
			if c != nil {
				accounts[*c] = true
			}
		}
		if len(accounts) > 1 {
			for customerId := range accounts {
				fmt.Println("flag for review:", customerId, cluster.GetMembers())
			}
		}
	}
}
require "fever_client"

FeverClient.configure do |config|
  config.scheme = "https"
  config.host = "your-appliance"
  config.access_token = "YOUR_API_KEY"
end

result = FeverClient::DuplicatesApi.new.find_duplicates(
  FeverClient::DuplicatesRequest.new(threshold: 0.92)
)
(result.duplicate_clusters || []).each do |cluster|
  accounts = cluster.member_customers.compact.uniq
  next unless accounts.size > 1
  accounts.each { |customer_id| puts "flag for review: #{customer_id} #{cluster.members}" }
end
import com.lowdownlabs.fever.ApiClient;
import com.lowdownlabs.fever.Configuration;
import com.lowdownlabs.fever.api.DuplicatesApi;
import com.lowdownlabs.fever.model.DuplicateCluster;
import com.lowdownlabs.fever.model.DuplicatesRequest;
import com.lowdownlabs.fever.model.DuplicatesResponse;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

public class FlagCrossAccountDupes {
    public static void main(String[] args) throws Exception {
        ApiClient client = Configuration.getDefaultApiClient();
        client.setBasePath("https://your-appliance");
        client.setRequestInterceptor(builder ->
            builder.header("Authorization", "Bearer YOUR_API_KEY"));
        DuplicatesApi api = new DuplicatesApi(client);

        DuplicatesResponse result = api.findDuplicates(
            new DuplicatesRequest().threshold(new BigDecimal("0.92")));
        for (DuplicateCluster cluster : result.getDuplicateClusters()) {
            Set<String> accounts = cluster.getMemberCustomers().stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toCollection(HashSet::new));
            if (accounts.size() > 1) {
                accounts.forEach(customerId ->
                    System.out.println("flag for review: " + customerId + " " + cluster.getMembers()));
            }
        }
    }
}
use std::collections::HashSet;

use fever_client::apis::{configuration::Configuration, duplicates_api};
use fever_client::models::DuplicatesRequest;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = Configuration {
        base_path: "https://your-appliance".to_owned(),
        bearer_access_token: Some("YOUR_API_KEY".to_owned()),
        ..Default::default()
    };
    let mut request = DuplicatesRequest::new();
    request.threshold = Some(0.92);
    let result = duplicates_api::find_duplicates(&config, request).await?;
    for cluster in result.duplicate_clusters.unwrap_or_default() {
        let accounts: HashSet<_> = cluster
            .member_customers
            .unwrap_or_default()
            .into_iter()
            .collect();
        if accounts.len() > 1 {
            for customer_id in &accounts {
                println!("flag for review: {customer_id} {:?}", cluster.members);
            }
        }
    }
    Ok(())
}
<?php
require_once __DIR__ . '/vendor/autoload.php';

use LowdownLabs\Fever\Api\DuplicatesApi;
use LowdownLabs\Fever\Configuration;
use LowdownLabs\Fever\Model\DuplicatesRequest;

$config = (new Configuration())
    ->setHost('https://your-appliance')
    ->setAccessToken('YOUR_API_KEY');
$api = new DuplicatesApi(null, $config);

$result = $api->findDuplicates(new DuplicatesRequest(['threshold' => 0.92]));
foreach ($result->getDuplicateClusters() ?? [] as $cluster) {
    $accounts = array_unique(array_filter($cluster->getMemberCustomers() ?? []));
    if (count($accounts) > 1) {
        foreach ($accounts as $customerId) {
            echo 'flag for review: ' . $customerId . ' ' . json_encode($cluster->getMembers()) . PHP_EOL;
        }
    }
}
using LowdownLabs.Fever.Api;
using LowdownLabs.Fever.Client;
using LowdownLabs.Fever.Model;

var config = new Configuration
{
    BasePath = "https://your-appliance",
    AccessToken = "YOUR_API_KEY"
};
var api = new DuplicatesApi(config);
var result = await api.FindDuplicatesAsync(new DuplicatesRequest(threshold: 0.92M));
foreach (var cluster in result.DuplicateClusters ?? new List<DuplicateCluster>())
{
    var accounts = (cluster.MemberCustomers ?? new List<string>())
        .Where(c => c != null)
        .Distinct()
        .ToList();
    if (accounts.Count > 1)
    {
        foreach (var customerId in accounts)
        {
            Console.WriteLine($"flag for review: {customerId} [{string.Join(", ", cluster.Members)}]");
        }
    }
}