Grooming detection
Most safety APIs answer “is this content sexual?” Tuteliq answers a stronger question: is this person being groomed — and how? Grooming is rarely a single message. It’s a structured sequence of tactics applied over time, each one independently low-severity but together unmistakable. Tuteliq’sdetect_grooming endpoint identifies six distinct tactics across a conversation, returns a per-message trajectory of risk score evolution, and produces a composite verdict with evidence-grounded flags.
This page is the deep-dive on what we detect and why each tactic matters.
The eight tactics
Each tactic below maps to aflags value returned by detect_grooming. Multiple tactics often co-occur — that co-occurrence is itself a strong predictor and a moderator’s most actionable signal.
reconnaissance is the newest tactic in the taxonomy (added in V3.1.0, 25 September 2026). It was already part of the published taxonomy, scored across a whole conversation. It is now also returned on the individual message that carries the probe, in any of the supported languages and in informal register.
Two things about it are worth knowing before you switch on it. A question that is only useful if the answer is “yes, supervised” is a safeguarding check, not a probe, so a tutor or coach confirming a guardian will be present is deliberately not flagged. And a single reconnaissance flag is not a completed profiling pattern: accumulation across a conversation is a separate capability and is not scored yet, so do not read one flag as an arc, or the absence of flags as the absence of probing.
meeting_request was the newest tactic before that (added in V3.15.0); earlier versions of the detector subsumed it under boundary_pushing. We separated it because the legal and operational response to a meeting attempt is materially different from boundary pushing: most platforms route meeting indications to immediate human review and trigger external reporting workflows, not just internal moderation.
Why the sequence matters
A single isolatedflattery flag from one message is rarely actionable on its own. The same flag combined with secrecy_request and isolation across a conversation is a near-certain grooming pattern that warrants immediate moderation. Tuteliq surfaces this in two ways:
1. Per-message trajectory. The response includes a message_analysis array with risk_score per message — allowing dashboards to plot the trajectory and surface the moment the pattern becomes unambiguous. A textbook grooming conversation shows a steady ramp from 0.1 to 0.9+ across rapport → secrecy → photo request → meeting attempt.
2. Multi-flag composite. Multiple flags on the same conversation are evidence of a pattern, not a noisy classifier. The endpoint’s risk_score reflects compounding when multiple tactics co-occur — the same content with two flags scores higher than the sum of two single-flag verdicts.
Conversation length
Two different limits apply, and it is worth keeping them apart. The schema limit is 100 messages. A call carrying more than that is rejected by request validation before any analysis runs, so it costs nothing and returns a validation error rather than a verdict. The practical ceiling is around 50 turns. Well inside the schema limit, long conversations start to strain the engine’s output budget. When the engine cannot produce a verdict it returns a graceful envelope rather than a 500:analysis_status: "engine_error", a zeroed risk_score, and a forced recommended_action: "flag_for_review".
That envelope is the correct response, and the zeroed score is not a verdict. A moderator
must NOT read an engine error as “no grooming detected”; the forced
flag_for_review exists precisely so the case cannot be silently passed.
For conversations beyond roughly 30 turns, use chunked sliding windows of 10 to 15 turns
and pass the continuation_token from each call back into the next, so trajectory state
is preserved across windows without resending history. See
Continuation tokens.
Age signals strengthen the verdict
Pass age information when you have it:context.child_age— the minor’s age (if known)context.participant_age— the non-minor counterpart’s age (if known, e.g. on age-verified platforms)messages[].sender_age— per-message age tag when conversations have more than two parties
grooming_risk: "none" and analysis_status: "out_of_scope_adults". This is a precision floor: adult-to-adult interactions with grooming-shaped content should be routed to /safety/coercive-control or /safety/social-engineering, not flagged as child grooming.
When not to use it
detect_grooming is purpose-built for adult-to-minor patterns in 1:1 or small-group conversations. It is not the right endpoint for:
- Peer-to-peer minor conversations. Use
/safety/bullyingor/safety/coercive-controlinstead — the prompt is calibrated for an age gap. - Romance scams targeting adults. Use
/fraud/romance-scam— the playbook overlaps superficially (rapport → isolation → ask) but the tactic vocabulary and intervention path are different. - Single-message analysis.
detect_groomingreasons over a conversation; a single message is rarely sufficient context. For single-message decisions, use/safety/unsafe.
Tactic mapping by severity
When designing moderator workflows, this severity ladder is a reasonable default:
Your specific routing should match your platform’s policy and the legal jurisdictions you operate in. The compound scoring in
risk_score already reflects this severity ranking — recommended_action is the operational shortcut.
Related
- Composable safety primitives — combine
detect_groomingwithdetect_vulnerability_exploitationfor vulnerability-amplified verdicts. - Continuation tokens — preserve trajectory state across chunked windows for long conversations.
- KOSA coverage — full mapping of detected tactics to KOSA harm categories.
- Languages — supported languages for
detect_grooming(currently 6+ at near-English parity).