Content classification
Score what people post (bios, messages, listings) for spam, phishing, malware and fraud.
COSS scores text with an AI model, per category: spam, phishing, malware and fraud. Each
score is the model's probability (0-1) that the text belongs to the category. COSS never turns the
scores into a verdict for you: you choose what they mean, with thresholds or rules.
Classify text on its own:
const { , } = await ..({ : . });
if ( && .. >= 0.8) {
// Hide the bio until someone looks at it.
}Or with an assessment, where the scores join every other signal:
const { } = await ..({
: "message",
: { : . },
: .,
: { : . },
});
// data?.signals.content: { spam: 0.02, phishing: 0.91, malware: 0.01, fraud: 0.12 }Thresholds and rules
Content scores in an assessment change nothing until you say what they mean:
- Thresholds (settings): at or above the threshold you
set for a category, the assessment gets
content.<category>(with the score asvalue), which counts in the score like any reason. Categories without a threshold never fire. - Rules:
content.spam,content.phishing,content.malwareandcontent.fraudare number fields, so a rule can block or review on a score directly.
await ...({ : { : 0.8, : 0.8 } });
await ...({
: "Scam listings",
: ["custom"],
: [{ : "content.fraud", : "gte", : 0.9 }],
: "block",
});The scores aren't calibrated against your traffic: start with high thresholds (0.8 or more), look at what they catch in the dashboard, and adjust.
Limits and failures
- The model reads the first 8,000 characters (
truncated: truewhen there were more). Links in the text are passed as host and path, without query strings. - A classification takes up to 3 seconds.
coss.risk.classify()returns a503(classification_unavailable) when the model fails or is slower, which the SDK retries; treat a persistent error as "unknown". An assessment never fails because of it: it goes on without the scores and listscontentindegraded. - Live classifications are limited per organization, to 10 per second (bursts of 20) and 10,000 per
day, across
coss.risk.classify()and assessments withcontent. Over the limit,classifyreturns a429(classification_rate_limited) and assessments go on without the scores (degraded). Sandbox classifications don't count.
Privacy
The text goes to the model (a decision model on Vercel's AI Gateway) with zero data retention, and COSS keeps it nowhere: not on the assessment, not in logs (they keep only its length), not in webhooks. Only the scores are stored, with the assessment.
Testing
Sandbox keys don't call the model: [coss-test:<category>] in the text scores 0.99 in that category,
[coss-test:<category>:<score>] exactly <score>, and everything else 0.01
(Testing).