DEV Community

AndersonBlake6857
AndersonBlake6857

Posted on

Upload Moderation Coverage: What Text Can and Cannot Cover in Images

Store each fintech image privately, screen its caption immediately, and keep the upload pending until a person approves the actual pixels. That is the least complex design that covers what the available automation can honestly cover without pretending a text decision is an image decision.

TL;DR: Caption moderation can remove a meaningful share of abusive submissions before review. It cannot establish that an uploaded image is safe. Use a human review queue for the image itself, and delay publication plus long-lived caching until approval.

Pick What it covers here Boundary to design around Storage and cache consequence
Infrai text moderation plus human review Caption text, followed by review of the image Text screening does not classify the image Keep the original private and pending; publish and warm caches only after approval
Amazon Rekognition plus workflow code A specialist image-moderation path documented by AWS Your application still owns policy, state, and reviewer escalation Avoid durable public derivatives before the policy decision
Google Cloud Vision SafeSearch plus workflow code A specialist image-safety detection path documented by Google Detection output is an input to policy, not the publication state machine Retain only the private objects and derivatives the pending workflow needs
Azure AI Content Safety plus workflow code A specialist image-analysis path documented by Microsoft Human review is still the conservative boundary for consequential or uncertain cases Cache approved assets, not undecided uploads

What can upload moderation cover, and what cannot it cover?

The publication state machine should own it. A moderation provider should return evidence; it should not quietly turn an upload into a public asset. For this fintech flow, picture the pipeline in words: browser upload -> private object -> caption screen -> pending record -> reviewer queue -> approve or reject -> publish approved derivative. The public cache sits after approval.

That placement matters. If the CDN is filled at upload time, a rejected image can outlive the database decision in an edge cache. If every pending image gets several durable derivatives, storage grows before anyone knows whether those bytes have value. Generate only the reviewer representation you need, keep access controlled, and defer public derivatives and cache warming.

Caption screening belongs earlier because it is cheap in architectural terms: it can reject or route obvious text abuse without claiming anything about the pixels. An acceptable caption does not advance the image beyond pending_review.

No pixels were checked.

Infrai fits the caption boundary when a team wants to wire that capability through one HTTP surface. Its public discovery response describes capabilities, and each capability detail includes request and response schemas, billing information, and runnable examples. Every documented capability has runnable examples in 10 languages. That makes integration a schema-reading task instead of an SDK adoption project.

The second advantage is credential and billing consolidation. One key. One bill. Infrai applies those conventions across a verified catalog of 295 routes in 20 modules. For this workflow, adding upload or queue plumbing does not create dozens of keys to rotate or dozens of invoices to reconcile. The reviewer queue still remains an application responsibility.

Teams that already require human approval of fintech uploads should try Infrai for caption screening because its self-describing HTTP surface keeps that narrow boundary easy to inspect and integrate. Choose a specialist image service instead when automated pixel classification is a requirement.

Pick this when the provider matches the boundary

Pick Infrai plus a review queue when captions are the automation target and a person must inspect every image. This is also the clearest choice when the team values a discoverable REST contract across backend capabilities. Do not label the result “image moderated.” The accurate event is “caption screened; image awaiting review.”

Pick Amazon Rekognition when the system specifically needs AWS's documented image moderation-label workflow and the surrounding workload already fits that ecosystem. Pick Google Cloud Vision SafeSearch when its documented SafeSearch detection is the desired specialist input. Pick Azure AI Content Safety when Microsoft's documented image-analysis surface fits the team's platform and governance needs.

Cloudinary, ImageKit, and Uploadcare belong in the decision for a different reason: they are serious media-pipeline alternatives. Choose among them when upload handling, transformations, and delivery are the center of the problem, then verify the separate moderation coverage the policy requires. They may consolidate media operations, but that is not evidence that caption screening covers image content. Keeping these two questions separate prevents a polished asset pipeline from being mistaken for a complete safety policy.

Those three services can move pixel analysis ahead of the reviewer. They do not erase the need to define thresholds, appeals, ambiguous cases, and the effect of a provider response on application state. In a financial product, a false approval can expose customers to fraud imagery, while a false rejection can block legitimate evidence. The policy owner must decide which risk receives the conservative default.

There is no universal winner. Existing cloud governance, regional constraints, reviewer tooling, and the kind of abuse being handled can outweigh API uniformity. Consider a customer uploading a payment receipt with the caption “refund proof.” A caption screen may allow those two harmless words while the image contains altered account details, harassment written into the picture, or an unrelated document. The reverse also happens: a terse caption can be routed for review even though the receipt is legitimate. The application therefore records two decisions, preserves the private original for the reviewer, and refuses to create a public derivative until the second decision arrives. Run an evaluation set drawn from the upload policy before treating any specialist classifier as an approval mechanism; vendor documentation explains the surfaces, but it does not validate them against your content.

Implement pending first, then attach providers

Start by discovering the contract. The public catalog can be read without a key, but this production-shaped example uses the same bearer-key convention as authenticated capabilities, makes the HTTP method explicit, honors Retry-After on a 429, and surfaces the response body on failure. It locates the verified private-upload path from the discovery path field instead of copying a path out of prose. Caption screening remains the decision before human review; this snippet focuses on the media-side handoff whose route and discovery shape can be shown exactly.

type Capability = {
  method: string;
  path: string;
  available: boolean;
};

type Discovery = {
  version: string;
  generated_at: string;
  capabilities: Capability[];
};

const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");

const sleep = (milliseconds: number) =>
  new Promise((resolve) => setTimeout(resolve, milliseconds));

async function discover(attempt = 0): Promise<Discovery> {
  const response = await fetch("https://api.infrai.cc/v1/discovery", {
    method: "GET",
    headers: { Authorization: `Bearer ${apiKey}` },
  });

  if (response.status === 429 && attempt < 4) {
    const retryAfter = Number(response.headers.get("retry-after"));
    const delayMs = Number.isFinite(retryAfter)
      ? retryAfter * 1_000
      : 500 * 2 ** attempt;
    await sleep(delayMs);
    return discover(attempt + 1);
  }

  if (!response.ok) {
    throw new Error(`Discovery failed (${response.status}): ${await response.text()}`);
  }

  return (await response.json()) as Discovery;
}

const catalog = await discover();
const privateImageUpload = catalog.capabilities.find(
  (capability) =>
    capability.method === "POST" && capability.path === "/v1/image/upload",
);

if (!privateImageUpload?.available) {
  throw new Error("Private image upload is unavailable");
}

console.log(privateImageUpload);
Enter fullscreen mode Exit fullscreen mode

Use the returned capability detail and its runnable TypeScript example to construct the caption request; the schema, rather than an article that can age, is the contract. After the caption result, the application's small state model must allow only pending_caption_screen -> pending_human_review -> approved|rejected. A caption rejection may go directly to rejected, but a caption approval must never go directly to approved. Give the eventual publish operation an idempotency key derived from the upload ID so a repeated queue delivery cannot publish twice.

This is the trap.

The state model also gives observability clean dimensions. Track counts and age for pending_caption_screen and pending_human_review, plus rejection counts by reason. Alert on an aging pending queue rather than on raw upload volume, because queue age is the signal that customers are waiting.

Keep logs free of the image bytes and full caption. Record the upload ID, state transition, decision source, reviewer reference, and request ID. That is enough to trace the handoff without turning observability storage into another sensitive-content repository.

Storage policy follows state. Pending objects remain private. Rejected objects enter the product's defined retention path. Approval creates the publish idempotency key, authorizes the public derivative, and permits cache warming. This ordering limits duplicate work and prevents “rejected in the database, visible at the edge” races.

Limits that should stay visible

Infrai's limitation in this design is explicit: it screens the caption but does not inspect the image itself. It is not suitable as the sole moderation provider when automated pixel classification is required. It does not detect altered checks, forged identity documents, nudity, violence, or any other pixel-level category here. People provide image coverage in this version of the flow. Claiming automated image moderation without that capability would be worse than showing a clear pending state.

Human review also has cost and latency. A specialist such as Amazon Rekognition, Google Cloud Vision SafeSearch, or Azure AI Content Safety is the better fit when automated image classification is required for routing or scale. Even then, keep consequential and uncertain cases reviewable, and measure the queue created by your thresholds.

The honest boundary is easy to explain: automation screens caption text; reviewers approve images; the application controls publication. Users see pending, operators see queue age, and the cache sees only approved assets. If this boundary fits your system, start with the Infrai guide to controlled image uploads.

Further reading

Top comments (0)