SwarmForensics API
Stop bot swarms before they hit your comments.
One API call per comment. SwarmForensics compares each new comment against your last 24 hours of activity and flags coordinated copy-paste waves, brigading bursts, and spam floods with a clear allow, review, or hold verdict.
500 free checks every month. No credit card required.
Detects coordination, not opinions
Signals come from timing, duplication, and account behavior. The content's viewpoint is never scored.
Fast and fail-open
One lightweight call per comment. Every error response still says action: "allow", so real users are never blocked by an outage.
No comment text stored
Only salted, text-free fingerprints are kept, and they are deleted automatically after 24 hours.
Pricing
Monthly plans, cancel any time. Usage resets on the 1st of each month (UTC). Checks stop at your plan limit, so there are no surprise overage bills.
Sandbox
Free
- 500 checks / month
- 30 requests / minute
- 2 active API keys
- Dashboard flags only
StarterPOPULAR
$19/mo
- 10,000 checks / month
- 120 requests / minute
- 5 active API keys
- Signed swarm-alert webhooks
Growth
$49/mo
- 50,000 checks / month
- 300 requests / minute
- 10 active API keys
- Signed swarm-alert webhooks
Scale
$149/mo
- 250,000 checks / month
- 600 requests / minute
- 25 active API keys
- Signed swarm-alert webhooks
Quickstart
- 1. Sign in and open Account → SwarmForensics API.
- 2. Create a key and store it as a server-side secret, for example
SEEDENV_SWARM_KEY. - 3. Call the API from your backend when a comment is submitted. Publish on
allow, queue onreview, and hide pending review onhold.
Never call the API from browser or mobile code. Anyone could read the key and spend your quota.
// Fail open: never block real users if the check is slow or unavailable.
export async function screenComment(comment) {
try {
const response = await fetch("https://seedenv.com/api/v1/moderate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SEEDENV_SWARM_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
text: comment.body,
authorId: comment.userId,
threadId: comment.postId,
commentId: comment.id,
}),
signal: AbortSignal.timeout(1500),
});
const verdict = await response.json();
return verdict.action; // "allow" | "review" | "hold"
} catch {
return "allow";
}
}Signals
Each signal adds weight to a 0–100 score. Defaults: 40+ is review, 70+ is hold.
- Copy-paste cluster
copy_paste_cluster - Identical text arrived from other accounts in the last 24 hours.
- Coordinated phrasing
coordinated_phrasing - Near-identical wording shared across several distinct accounts.
- Burst window
burst_window - Matching comments from multiple accounts landed within 10 minutes.
- Same-thread brigade
same_thread_brigade - Matching accounts converged on one thread at the same time.
- Author flood
author_flood - One author posted an unusual number of comments in 10 minutes.
- Self repeat
self_repeat - One author pasted the same text into several different threads.
- Link heavy
link_heavy - Several links, or links from a brand-new account.
- New account
new_account - Amplifier only: the author is under 2 days old and other signals fired.
Signals are statistical indicators, not proof of automation. Organic viral moments can look bursty, so pair holds with human review.
API reference
POST https://seedenv.com/api/v1/moderate
Authenticate with Authorization: Bearer sfk_live_… (or X-API-Key). JSON body up to 20 KB.
| Field | Type | Description |
|---|---|---|
| text | string, required | The comment body, up to 5,000 characters. Used to compute a fingerprint and never stored. |
| authorId | string, required | Your stable ID for the commenter. Hashed with a per-account salt. |
| threadId | string | The post, video, or thread the comment belongs to. Enables brigade detection. |
| commentId | string | Your comment ID. Echoed back and shown in the dashboard so you can match flags. |
| postedAt | ISO 8601 | When the comment was posted. Defaults to now; values outside the last 24 hours are clamped. |
| authorAccountAgeDays | number | Age of the commenter's account. Amplifies other signals for brand-new accounts. |
| thresholds | { review, hold } | Override the default scores (40 / 70) that map to review and hold. |
Request
curl -X POST https://seedenv.com/api/v1/moderate \
-H "Authorization: Bearer $SEEDENV_SWARM_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "This update is a scam, everyone cancel now",
"authorId": "user_8812",
"threadId": "post_311",
"commentId": "c_90211",
"authorAccountAgeDays": 0.4
}'Response
{
"id": "mod_cm3x…",
"commentId": "c_90211",
"action": "hold",
"score": 82,
"signals": [
{ "code": "copy_paste_cluster", "weight": 30, "detail": "Identical text posted by 4 other accounts in the last 24h." },
{ "code": "coordinated_phrasing", "weight": 30, "detail": "Near-identical phrasing shared with 4 other accounts." },
{ "code": "burst_window", "weight": 20, "detail": "4 matching accounts posted within 10 minutes." }
],
"cluster": { "size": 4, "sameThread": 4, "inBurstWindow": 4 },
"thresholds": { "review": 40, "hold": 70 },
"plan": "STARTER",
"usage": { "used": 1288, "limit": 10000, "remaining": 8712, "resetsAt": "2026-12-01T00:00:00.000Z" }
}Errors
Errors use { error: { code, message }, action: "allow" } so fail-open handling is one line.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_json / invalid_request | Body is not JSON or a field failed validation. |
| 401 | unauthorized | Missing, invalid, or revoked API key. |
| 413 | payload_too_large | Body is larger than 20 KB. |
| 429 | rate_limited | Per-minute limit hit. Honor the Retry-After header. |
| 429 | quota_exceeded | Monthly allowance spent. Checks resume on the 1st (UTC) or after upgrading. |
| 500 | internal_error | Temporary failure. Fail open and retry later. |
Webhooks
On paid plans, add an HTTPS endpoint in your dashboard. When a comment is held we POST a comment.held event with the moderation ID, your comment, thread, and author IDs, the score, signals, and cluster size. Each request carries a SeedEnv-Signature header. Verify it and reject anything older than 5 minutes.
import { createHmac, timingSafeEqual } from "node:crypto";
// Header: SeedEnv-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "t.rawBody">
export function verifySeedEnvSignature(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest();
const received = Buffer.from(parts.v1 ?? "", "hex");
return received.length === expected.length && timingSafeEqual(received, expected);
}Privacy & acceptable use
- Comment text is used only to compute a fingerprint and is never stored.
- Fingerprints use a random salt unique to your account, are never shared across customers, and are deleted after 24 hours.
- You are responsible for disclosing automated moderation in your own privacy policy where required.
- The API may not be used to suppress lawful speech based on viewpoint, or to target individuals.
FAQ
Does it filter political opinions?
No. SwarmForensics never scores what a comment says or which side it takes. It looks only for coordination patterns, such as many accounts posting the same text in a short burst, which works the same for spam, astroturfing, and brigades of any viewpoint.
Will it delete comments automatically?
No. The API returns a recommendation. We suggest holding high scores for human review rather than deleting them, because heuristics can produce false positives during genuinely viral moments.
What data do you store?
We never store comment text. Each check keeps a short-lived fingerprint (salted hashes of the author, thread, text, and words) for 24 hours so we can spot coordination across comments, then it is deleted automatically.
What happens when I hit my limit?
Requests return 429 quota_exceeded with action "allow" so your app keeps working. Upgrade any time, or wait for the monthly reset on the 1st (UTC).
Is the free paste tool still free?
Yes. The SwarmForensics paste tool stays free, runs in your browser, and needs no account. The API is for apps that want continuous, automatic screening.
Start screening comments today
Free sandbox key in under a minute. Upgrade when your traffic does.