Spam Detection
Detect spam comments in your discussions.
Every comment gets one of three outcomes:
| Outcome | Response | What to do |
|---|---|---|
| Spam | is_spam is true | Delete it. |
| Suspected spam | is_spam is false, suspected_spam is true, suggestion is filled in | Send it back to the commenter with the suggestion, as you would a comment that needs revision. A real person can fix it and post again; a spammer won't bother. |
| Not spam | is_spam and suspected_spam are both false | Publish it as normal. |
What it detects:
- Promotional/advertising content
- Bot-generated text patterns
- Link spam and SEO manipulation
- Repeated/duplicate comments
- Off-topic noise
Reference
See the Spam Detection API Reference for method signatures and parameters.
Response: SpamDetectionResult
By Example
Basic Usage
- TypeScript
- Python
- PHP
- REST API
// With article context (more accurate)
const result = await client.checkSpam(
"Buy cheap watches at example.com!",
articleId
);
// Without context (standalone check)
const result2 = await client.checkSpam("Buy cheap watches at example.com!");
console.log(`Is spam: ${result.is_spam}`);
console.log(`Confidence: ${result.confidence.toFixed(2)}`);
console.log(`Reasoning: ${result.reasoning}`);
if (result.is_spam) {
// Delete it
} else if (result.suspected_spam) {
// Send it back to the commenter with result.suggestion
} else {
// Publish it
}
- Blocking Client
- Async Client
# With article context (more accurate)
result = client.check_spam(
"Buy cheap watches at example.com!",
article_id
)
# Without context (standalone check)
result = client.check_spam("Buy cheap watches at example.com!")
print(f"Is spam: {result.is_spam}")
print(f"Confidence: {result.confidence:.2f}")
print(f"Reasoning: {result.reasoning}")
if result.is_spam:
... # Delete it
elif result.suspected_spam:
... # Send it back to the commenter with result.suggestion
else:
... # Publish it
# With article context (more accurate)
result = await client.check_spam(
"Buy cheap watches at example.com!",
article_id
)
# Without context (standalone check)
result = await client.check_spam("Buy cheap watches at example.com!")
print(f"Is spam: {result.is_spam}")
print(f"Confidence: {result.confidence:.2f}")
print(f"Reasoning: {result.reasoning}")
if result.is_spam:
... # Delete it
elif result.suspected_spam:
... # Send it back to the commenter with result.suggestion
else:
... # Publish it
$client->checkSpam("Buy cheap watches at example.com!", $articleId)
->then(function ($result) {
echo "Is spam: " . ($result->isSpam ? 'Yes' : 'No') . "\n";
echo "Confidence: " . number_format($result->confidence, 2) . "\n";
echo "Reasoning: " . $result->reasoning . "\n";
if ($result->isSpam) {
// Delete it
} elseif ($result->suspectedSpam) {
// Send it back to the commenter with $result->suggestion
} else {
// Publish it
}
});
$client->run();
# With article context (more accurate)
curl -X POST https://app.respectify.ai/v0.2/antispam \
-H "X-User-Email: your@email.com" \
-H "X-API-Key: your-api-key" \
-d "comment=Buy cheap watches at example.com!" \
-d "article_context_id=550e8400-e29b-41d4-a716-446655440000"
# Without context (standalone check)
curl -X POST https://app.respectify.ai/v0.2/antispam \
-H "X-User-Email: your@email.com" \
-H "X-API-Key: your-api-key" \
-d "comment=Buy cheap watches at example.com!"
Response for spam:
{
"is_spam": true,
"confidence": 0.95,
"reasoning": "Classified as spam by first-pass screening.",
"suspected_spam": false,
"suggestion": ""
}
Response for suspected spam, here a comment with a link:
{
"is_spam": false,
"confidence": 0.3,
"reasoning": "",
"suspected_spam": true,
"suggestion": "This looks like spam. How about removing the link?"
}
Response for a comment that is not spam:
{
"is_spam": false,
"confidence": 0.97,
"reasoning": "",
"suspected_spam": false,
"suggestion": ""
}
First-Pass Screening
Spam is decided by a fast first-pass screen alone. No comment is sent for a fuller assessment of spam: spam needs a verdict, not an explanation. The screen gives each comment a probability of being spam, and that decides the outcome:
- 0.85 or above, spam:
is_spamistrue,confidenceis the screen's probability, andreasoningis "Classified as spam by first-pass screening." The cutoff is set high so that real comments are not deleted. - 0.50 up to 0.85, suspected spam:
is_spamisfalse,suspected_spamistrue, andsuggestionholds a short message for the commenter.confidenceis the confidence that it is not spam, andreasoningis empty. - Below 0.50, not spam:
is_spamandsuspected_spamarefalse,confidenceis the confidence that it is not spam, andreasoningandsuggestionare empty, since there is nothing to explain.
The suggestion for a suspected-spam comment is one of two:
- If the comment contains a link: "This looks like spam. How about removing the link?"
- Otherwise: "This reads like promotion. How about saying what you think about the discussion?"
If screening is unavailable, the comment is let through rather than deleted without a verdict: is_spam is false, confidence is 0, and reasoning is "Not checked for spam: screening was unavailable." A check that was not screened is not charged.
In a megacall, a comment answered as spam ends the request: every other check is returned as null and only the spam check is charged. A suspected-spam comment is not spam, so the other checks still run and are returned as usual.
Best Practices
- Use article context when available for better accuracy.
- Act on the outcome, not the confidence. Respectify has already applied the thresholds: delete when
is_spamistrue, send the comment back whensuspected_spamistrue, and publish otherwise. - Show the suggestion to the writer of a suspected-spam comment, alongside any other feedback for the comment (for example from comment health), so they can fix it and post again.
- Log false positives to understand patterns.