Skip to content

Moderate images

Send an image by URL. Infrared fetches it, screens the picture and reads the text inside it. The result arrives by webhook or by polling.

Send an image as a URL: an upload on your CDN, or a signed link to private storage. Infrared fetches the file, screens the picture and reads any text in it. That takes longer than reading text, so by default the request answers at once with 202 and the result follows.

curl https://api.useinfrared.com/v1/moderations \
  -H "Authorization: Bearer $INFRARED_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "image",
    "input": "https://cdn.example.com/uploads/table-1.jpg",
    "content_id": "photo_5512"
  }'
202 Accepted, trimmedJSON
{
  "object": "moderation",
  "id": "mod_5E7NCoxdjAvNOge9s13Bna",
  "template": { "slug": "basic", "version": 1 },
  "type": "image",
  "status": "screening",
  "flagged": false,
  "recommendation": null,
  "severity": null,
  "policies": {},
  "content_id": "photo_5512",
  "created_at": "2026-10-08T08:56:18.344Z",
  "completed_at": null
}

Keep the id. When the run ends, a moderation.completed webhook event carries the finished moderation, and GET /v1/moderations/{id} returns it whenever you ask.

curl https://api.useinfrared.com/v1/moderations/mod_5E7NCoxdjAvNOge9s13Bna \
  -H "Authorization: Bearer $INFRARED_KEY"
200 OK, trimmedJSON
{
  "object": "moderation",
  "id": "mod_5E7NCoxdjAvNOge9s13Bna",
  "type": "image",
  "status": "completed",
  "flagged": false,
  "recommendation": "allow",
  "severity": "none",
  "policies": {
    "violence": 0,
    "self_harm": 0,
    "sexual": 0,
    "illicit": 0,
    "toxicity": 0,
    "hate_speech": 0,
    "profanity": 0,
    "spam": 0
  },
  "triggered": [],
  "reasons": ["triage:allow"],
  "details": {
    "violence": { "explanation": "A modern wooden table with white chairs and a magazine titled 'INVENTORY' resting on top." },
    "profanity": { "labels": ["ocr"] }
  },
  "language": null,
  "usage": { "checks": 0, "cached": false }, // sent with a test key; a live key uses 2
  "test": true,
  "content_id": "photo_5512",
  "completed_at": "2026-10-08T08:56:25.942Z"
}

The photo shows a table with a magazine on it. The four image policies scored the picture, and the title on the magazine cover was read and passed to the profanity lexicon, which is what the ocr label records.

One image or several

A request without field takes exactly one URL; a list of two is answered as an invalid submission. To send several images at once, name an image field of the template and pass a list. On the basic check that field is image and it takes up to ten.

curl https://api.useinfrared.com/v1/moderations \
  -H "Authorization: Bearer $INFRARED_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "image",
    "field": "image",
    "input": [
      "https://cdn.example.com/uploads/table-1.jpg",
      "https://cdn.example.com/uploads/table-2.jpg"
    ]
  }'

Each image is screened on its own and the moderation keeps the highest score per policy. Photos that belong to a larger object, such as a listing with a title and a price, go in a form.

How the image is fetched

  • The URL starts with http:// or https:// and holds no spaces. Images cannot be sent inline.
  • The file may be up to 10 MB and must arrive within 10 seconds.
  • Up to three redirects are followed.
  • The host must resolve to a public address. Loopback, private and link-local addresses are refused, also after a redirect.
  • The type is read from the file's first bytes, never from Content-Type: JPEG, PNG, WebP and GIF are accepted. An animated image is screened by its first frame.
  • The fetch identifies itself as Infrared-Moderation/1.0.

The URL is not fetched before the API answers. One that turns out to be unreachable, too large or not an image still answers 202; the moderation then ends partial with a review recommendation and uses its checks. details carries the reason under each image policy, for example HTTP 404 fetching media.

When one of several images in a field cannot be fetched, the others are screened and the status stays completed. In a form, the failed URL is listed in that field's validation_errors; a single-object request does not report it.

What is screened

One call per image looks at the picture, with your project's context and the field's description beside it. It scores:

  • the image policies the template enables: violence, self_harm, sexual and illicit. These four are what the basic check runs on an image.
  • the image signals a template can add: screenshot, image_quality, watermark, and links_contact for a picture whose main purpose is to show contact details.
  • made_with_ai, on Growth and up. It is experimental and observes by default.

The same call returns a one-sentence description of the picture. It is in details as explanation, repeated under every policy the call scored.

Text inside the image

The call also reads the text in the picture, and that text is screened without a second request:

  • Wordlists, the profanity lexicon and lookalike_characters read it at full strength.
  • links_contact and personal_data read it according to their image_text option. By default a phone number in a photo is reported as evidence with a low score and cannot trigger on its own. Policy options lists the three settings.
  • The template's AI instructions and your guidelines see it together with the other fields.

Every finding that came from image text carries the label ocr. Image text is not scored for toxicity, hate_speech or spam; those policies read text fields only.

Wait for the result in the request

Set mode to sync and the request stays open until the image is screened, then answers 200 with the finished moderation. The images of one field are fetched and screened one after another, so the wait grows with their number. Sync and async compares the two ways.

Cost

An image request uses one check for the object and one more per image: two for a single image, four for three images in one request. made_with_ai adds one per image. The same file in the same field is served from the result cache for six hours at a quarter of the checks; the file is still fetched each time.

In the dashboard

Open the moderation in the Live console to see the picture next to its scores. Stored images are shown blurred. Revealing the original takes a click and is written to the audit log.

The Media section of a listing with two photos, both blurred, each with an eye button that shows the original.
Dashboard, Live consoleThe media of an image moderation. Pictures arrive blurred, and the eye on a tile shows the original.

On a plan that stores no content, the picture is screened and not kept. Data retention says what is stored and for how long.

Next

Something missing or unclear on this page? Write to support@useinfrared.com.