How predictions work

image ──► 1. Decode ──► 2. Detect cat ──► 3. Classify ──► response
                           │                  │
                           │                  └─ only when detection == "detected"
                           └─ picks the single most confident cat

Detection

A cat detector looks for cats in the image. If there are several, it uses the one it is most confident about. The outcome is reported in detection:

detection Detector confidence for the best cat cat prediction What to do
detected ≥ 0.69 present present Use the prediction.
low_confidence 0.5 – < 0.69 present (best candidate) null Ask the user for a clearer, closer photo. You can use cat.bounding_box to show where the candidate was found.
not_detected no cat at ≥ 0.5 null null Tell the user no cat was found.

All three outcomes are successful requests (HTTP 200). Check detection before reading prediction.

Classification: score, threshold, label

When a cat is detected, the classifier looks at the cropped cat and produces:

  • score: the probability (0.0–1.0) that the cat shows discomfort.
  • threshold: the cut-off used for this request.
  • label: "discomfort" when score > threshold (strictly greater), otherwise "comfort".

Choosing a threshold

  • If you omit threshold, the model's trained default is used. That is currently 0.3 for bc-v1, but it can change when the model is retrained. Always read prediction.threshold from the response rather than assuming a value.
  • Lower threshold → more cats flagged as discomfort (fewer missed cases, more false alarms). Suits triage and screening.
  • Higher threshold → fewer flags (more certain flags, more missed cases).
  • Because score is returned, you can also apply your own threshold on your side without calling the API again.

Bounding box coordinates

cat.bounding_box is in pixels of the image as it was decoded:

  • The origin (0, 0) is the top-left corner. x increases to the right and y increases downward.
  • x_min, y_min are the top-left corner of the box. x_max, y_max are the right and bottom edges.
  • Values are integers. image.width and image.height give the frame they refer to.

To draw the box on a differently sized preview, scale it:

const scaleX = previewWidth / result.image.width;
const scaleY = previewHeight / result.image.height;
const box = result.cat.bounding_box;
drawRect(box.x_min * scaleX, box.y_min * scaleY,
         (box.x_max - box.x_min) * scaleX, (box.y_max - box.y_min) * scaleY);

⚠️ Photo orientation (EXIF): the API does not apply EXIF orientation tags. Phone cameras often store images sideways with a "rotate" tag. If you send such a file, coordinates refer to the unrotated pixels. Rotate images upright before sending them (see Image best practices).

Request IDs

Every v2 response includes a request ID in the X-Request-ID response header and in the request_id field of the body. This applies to successes and errors, including 401s.

  • You can supply your own ID by sending an X-Request-ID request header. It must be 1–128 characters of letters, digits, ., _, :, or -.
  • If you don't send one, or yours doesn't match those rules, the API generates one (format req_<32 hex characters>). An invalid ID never causes a request to fail.
  • Log the request ID and include it when contacting support.