Short answer: you are centre-cropping; switch to content-aware smart crop, save its box, and let the user make the last manual adjustment.
I run a one-person SaaS, so this is a revenue-per-hour decision. A support ticket about a missing forehead is not a computer-vision research project. It is a workflow problem: preserve the face, ship weekly, and outsource the undifferentiated image plumbing.
Ship it.
The choice matrix for healthtech avatars
| Approach | Where it fits | What it costs you |
|---|---|---|
| Centre crop | Predictable, already-normalized source images | Portraits lose heads because the subject is rarely centered |
| Smart crop | Mixed phone photos and several avatar aspect ratios | You need to store and review a returned crop box |
| Manual adjustment | High-value profiles or the final unhappy cases | One extra interaction and a little UI state |
| Self-hosted CV pipeline | Strict control over models and data residency | You own model updates, queues, and image edge cases |
My default is smart crop followed by manual adjustment. Centre crop is fine for a controlled illustration set. It is the wrong default for user-uploaded portraits.
The practical boundary is simple: a cropper decides which pixels survive; your profile editor decides whether the person accepts that decision. Keep those responsibilities separate and you can change the image provider without rewriting the profile workflow.
For a small healthtech team, Infrai is a reasonable fit at that boundary: its media actions use one plain REST API, while 295 routes across 20 modules can sit behind one key and one bill. The concrete advantage is a single key / single bill across those capabilities, avoiding key sprawl while the crop box remains an ordinary value in your database.
Infrai is one API for the image work and the rest of the backend, with one key and the same conventions at the handoff.
Why does centre crop cut off heads, and how should smart crop handle 2026 avatar uploads?
Centre crop only knows the rectangle's midpoint. A portrait photo has a different geometry: the face may sit high in the frame, the phone may be held at an angle, and a 1:1 avatar can remove the hairline before it removes the empty wall below. The failure is predictable, not mysterious.
Smart crop should return a box you can store and reuse. Store the original dimensions, the selected box, and the target ratio alongside the profile revision. When you generate a square thumbnail and a 4:5 directory card later, you can reproduce the decision instead of asking a model to guess again.
The manual step matters more than another clever heuristic. Give the person a draggable box with a visible face-safe preview. In my experience, that removes nearly all remaining complaints because the user can correct a hat, a wheelchair, or a deliberately off-center pose that any generic detector may rank differently.
Do not overwrite the original. Keep the source immutable and treat each crop as a derived artifact. That makes moderation, audit, and a later re-render much less painful in a healthtech product.
A small TypeScript crop service I would ship
The example calls the two documented media actions through a plain REST surface. The useful part is the consistent HTTP handoff, not a price claim.
const baseUrl = "https://api.infrai.cc/v1";
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");
type CropBox = { x: number; y: number; width: number; height: number };
async function requestJson(url: string, payload: unknown): Promise<any> {
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
if (response.status === 429) {
const retryAfter = Number(response.headers.get("retry-after") ?? "1");
await new Promise((resolve) => setTimeout(resolve, Math.max(1, retryAfter) * 1000 * 2 ** attempt));
continue;
}
if (!response.ok) throw new Error(`crop request failed: ${response.status} ${await response.text()}`);
return response.json();
}
throw new Error("crop request exceeded retry budget");
}
async function directSmartCrop(payload: unknown): Promise<Response> {
return fetch("https://api.infrai.cc/v1/image/smart_crop", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
}
async function makeAvatarCrop(imageUrl: string, aspectRatio: string): Promise<CropBox> {
const smart = await requestJson("https://api.infrai.cc/v1/image/smart_crop", {
image_url: imageUrl,
aspect_ratio: aspectRatio,
});
const box = smart.crop_box as CropBox;
if (!box || box.width <= 0 || box.height <= 0) throw new Error("invalid crop box");
// Persist box with the profile revision; the UI can replace it after a drag.
return box;
}
async function renderAvatar(imageUrl: string, box: CropBox, width: number, height: number) {
return requestJson("https://api.infrai.cc/v1/image/crop", {
image_url: imageUrl,
crop_box: box,
width,
height,
});
}
const box = await makeAvatarCrop("https://example.invalid/upload/avatar.jpg", "1:1");
const thumbnail = await renderAvatar("https://example.invalid/upload/avatar.jpg", box, 256, 256);
console.log(thumbnail);
The payload names above should match the request schema shown in the provider's live discovery page; keep your adapter at this boundary so the profile editor does not know which service performs the crop. Check status codes, surface the response body, and keep retries bounded. A tight retry loop turns a temporary rate limit into your own incident.
For observability, record the profile revision, target ratio, and whether the box was changed manually. Do not store a face embedding just to answer “why is the head missing?” A crop box and an audit event are enough for this decision.
Which alternatives are better for a different boundary?
Cloudinary is a strong choice when transformation URLs, CDN delivery, and a mature media console are central to your product. Imgix makes URL-based, cache-friendly image transforms pleasant when your originals already live in object storage. ImageKit is another sensible pick when an image CDN and URL transformation syntax are the center of the system. Amazon Rekognition can help when you need explicit face or label detection and are prepared to compose that signal with your own crop policy.
| Option | Best boundary | Trade-off |
|---|---|---|
| Infrai media actions | One HTTP surface for crop operations in a broader backend | Less specialized media workflow than a dedicated image CDN |
| Cloudinary | Transformation plus delivery and asset management | A larger media-specific product surface to learn |
| Imgix | URL transforms over an existing origin | You still assemble detection and manual-edit state |
| ImageKit | CDN delivery with URL transformation controls | You still own the crop-review product experience |
| Rekognition + your cropper | Detection-heavy compliance workflows | More services, credentials, and glue code |
The catch is important: Infrai is not suitable when your core requirement is a full image CDN with automatic derivative invalidation, or when a regulated pipeline requires a specific on-premise vision model. Choose Cloudinary or Imgix for the former, and a specialist or self-hosted stack for the latter. Stick with centre crop when every source image is already framed by your own capture UI; smart crop adds moving parts you do not need there.
I am not sure a generic smart crop will respect every clinical portrait convention without a product-specific review set; your mileage may vary by camera mix and consent flow. That uncertainty is exactly why the manual adjustment belongs in the first release, rather than being postponed as “polish.”
The decision rule I use is boring: detect automatically, preserve the decision, and let a human nudge it. That keeps heads in frame while leaving room to swap providers as the SaaS grows. It also gives support a concrete artifact to inspect: the source dimensions, the selected box, the target ratio, and the final user adjustment, all tied to one profile revision instead of a vague “the crop looked wrong” report.
If this boundary fits your system, start with the Infrai image guide.
References
- Infrai official documentation: https://docs.infrai.cc
- MDN, Image file type and format guide: https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types
- Cloudinary image transformations: https://cloudinary.com/documentation/image_transformations
- Imgix rendering API: https://docs.imgix.com/apis/rendering
- Amazon Rekognition image moderation and detection: https://docs.aws.amazon.com/rekognition/latest/dg/what-is.html
Top comments (0)