Skip to Content
SFW API

Analyze endpoint

POST /v1/analyze — inputs (URL, base64, multipart), options (max_frames, include_frames, policy) and the full response.

POST https://api.sfwapi.dev/v1/analyze

Input

Exactly one media source per request:

HowBodyNotes
URL{"url": "https://…"}Public http(s) URL. Our servers download it; redirects are followed up to 3 hops; private and local addresses are refused.
Uploadmultipart field filePreferred for files you already hold. The file name you send is discarded.
Base64{"base64": "…"}Convenient from a canvas; costs about a third more bandwidth than an upload. A data: prefix is stripped.

Options (JSON fields, or form fields on multipart):

FieldTypeDefaultMeaning
max_frames1–325 for GIF, 10 for videoFrames sampled evenly over the clip (first and last always included). One credit per analysed frame.
include_framesbooleanfalseReturn frames[] with per-frame scores and levels.
policyobjectnoneSee Policies. On multipart, send it as a JSON string.

Accepted media: JPEG, PNG, WebP, GIF, BMP, TIFF, AVIF, HEIC, MP4, MOV, WebM, MKV, AVI. Size limits depend on your tier (free: 8 MB, no video; paid: 32 MB uploads, 32 MB images, 64 MB GIFs and videos by URL). Sync requests time out after 60 seconds.

Response

{
  "id": "an_01JD4Q0K7X3Y9Z8W2V1U0T9S8R",
  "media": { "kind": "gif", "width": 480, "height": 270, "frames_analyzed": 5, "duration_ms": 2400 },
  "nudity": { "level": 2, "scores": { "revealing": 96.2, "implied_nudity": 71.5, "explicit": 8.1 } },
  "flags": { "art": { "score": 3.4, "detected": false }, "sex_object": { "score": 0.9, "detected": false } },
  "policy": { "blocked": true, "reason": "level", "matched_level": 2 },
  "frames": [ { "index": 0, "timestamp_ms": 0, "level": 0, "scores": { "…": 0 }, "flags": { "…": 0 } } ],
  "usage": { "credits": 5, "balance": 9995 },
  "timing_ms": { "upstream": 1840, "total": 1862 }
}
  • nudity.level: highest level whose score is above 50 in any frame.
  • nudity.scores: maximum over frames per level threshold.
  • flags.*.detected is score > 50.
  • policy appears only when a policy was sent; reason is level, sex_object or art_level.
  • frames appears only with include_frames: true.

Headers: X-Request-Id (quote it to support), X-Credits-Remaining, RateLimit, RateLimit-Policy, Retry-After on 429/503.

The machine-readable contract is at /openapi.json; an interactive reference lives at api.sfwapi.dev/reference.

On this page