Should spam comments be deleted or queued?
Queue borderline comments and only reject very high probabilities. Keeping a rejected or reviewed record gives moderators an audit trail and lets you tune thresholds against your own community.
use case · user comments
Updated May 12, 2026
Comment sections are unique: a wrongly-blocked legitimate comment is public and visible. False positives drive engaged users away. The right tool is a calibrated probability you can route through three buckets — publish, hold, reject — not a binary classifier that forces you to pick one side of an awkward tradeoff.
Run every comment through /v1/predict on submission. Compare against two thresholds:
needs_review; show to the author but not to the public, surface in your moderation queue.rejected status (rather than deleting) lets you audit the model's behaviour later.The exact thresholds depend on your appetite for false positives. Communities like dev forums (where every comment matters) skew conservative; review sections on a marketplace can be more aggressive. Tune on your own queue.
The pattern uses the official siftfy Python client — see SDKs. Two opinionated choices: trusted users skip the API entirely (cheap and noticeable on volume), and any Siftfy-side failure routes the comment to review rather than publishing it raw.
# Flask handler for POST /api/comments
import os
from flask import Flask, request, jsonify
from siftfy import Siftfy, RateLimitError, APIError
app = Flask(__name__)
client = Siftfy(api_key=os.environ["SIFTFY_KEY"], timeout=2.0)
SPAM_THRESHOLD = 0.90 # high bar — false-blocks burn your community
QUEUE_THRESHOLD = 0.60 # send to mod queue between QUEUE and SPAM
@app.post("/api/comments")
def post_comment():
body = request.json
text = body.get("body", "").strip()
user_id = body["user_id"]
if not text:
return {"error": "body required"}, 400
# Established trusted users skip classification entirely. Cheap to
# implement (a single query against your "verified" table) and saves
# a Siftfy call on the bulk of legitimate traffic.
if user_is_trusted(user_id):
return save_comment(body, status="published")
probability = 0.0
try:
result = client.predict(text)
probability = result.spam_probability
except RateLimitError:
# Hit our minute cap. Fall through to "queue" so a human eyeballs it.
return save_comment(body, status="needs_review", reason="ratelimit")
except APIError as e:
# Server-side issue at Siftfy. Log and queue for review rather than
# letting raw user content go straight to publish.
app.logger.warning("siftfy %s rid=%s", e.status_code, e.request_id)
return save_comment(body, status="needs_review", reason="siftfy-error")
if probability >= SPAM_THRESHOLD:
return save_comment(body, status="rejected", probability=probability)
if probability >= QUEUE_THRESHOLD:
return save_comment(body, status="needs_review", probability=probability)
return save_comment(body, status="published", probability=probability)Siftfy classifies the comment text. Stack your own metadata signals on top:
Combine these with the spam probability into a single moderation score; the calibrated 0–1 output makes that math straightforward.
request_id from the Siftfy response with the comment row — it's the only handle for support tickets.Queue borderline comments and only reject very high probabilities. Keeping a rejected or reviewed record gives moderators an audit trail and lets you tune thresholds against your own community.
Yes, if you have a reliable trust signal. Established authors, verified customers, or staff can skip the API call so moderation effort stays focused on unknown or risky traffic.
For public comments, fail closed into moderation review rather than publishing unclassified text. The user can still see a normal submission result while moderators inspect the queue.
See the EchoThread integration for the same pattern in production, or read /v1/predict for the full request/response shape. Background reading: moderation playbook, comment spam & SEO.