Process user-generated content for moderation

View Markdown

Every upload needs to be screened before it goes live. โ€œFeedloopโ€ (a social platform like Reddit or TikTok) processes thousands of video uploads per hour and routes each one through a review queue with representative thumbnails and a web-ready transcode.

Step 1: Extract thumbnails at intervals

Pull frames at regular intervals so moderators can scan the video without watching it:

ittybit image \
  -i https://feedloop-app.com/uploads/user-video-8812.mp4 \
  --start 2 \
  --width 640 \
  --format webp
const thumbnails = [2, 10, 30, 60].map((start) => ({
  input: 'https://feedloop-app.com/uploads/user-video-8812.mp4',
  kind: 'image',
  options: {
    start,
    width: 640,
    format: 'webp',
  },
}));

for (const task of thumbnails) {
  const res = await fetch('https://api.ittybit.com/jobs', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.ITTYBIT_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(task),
  });
  const data = await res.json();
}
import requests

api_key = "your_api_key"

for start in [2, 10, 30, 60]:
    task = {
        "input": "https://feedloop-app.com/uploads/user-video-8812.mp4",
        "kind": "image",
        "options": {
            "start": start,
            "width": 640,
            "format": "webp",
        },
    }

    res = requests.post(
        "https://api.ittybit.com/jobs",
        headers={"Authorization": f"Bearer {api_key}"},
        json=task,
    )
    data = res.json()
TASK='{
  "input": "https://feedloop-app.com/uploads/user-video-8812.mp4",
  "kind": "image",
  "options": {
    "start": 2,
    "width": 640,
    "format": "webp"
  }
}'

curl -X POST https://api.ittybit.com/jobs \
  -H "Authorization: Bearer $ITTYBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$TASK"

Repeat with start values at 10, 30, and 60 to cover the full video. Moderators see a filmstrip without downloading the original.

Step 2: Transcode for the review player

Moderators need a lightweight preview. Transcode to a capped resolution so the review UI loads fast:

{
  "input": "https://feedloop-app.com/uploads/user-video-8812.mp4",
  "kind": "video",
  "options": {
    "width": 720,
    "format": "mp4",
    "quality": "medium"
  }
}

CLI

Run both steps locally:

# Thumbnails at 2s, 10s, 30s, 60s
for t in 2 10 30 60; do
  ittybit image \
    -i user-video-8812.mp4 \
    -o "thumb-${t}s.webp" \
    --start $t \
    --width 640
done

# Review-quality transcode
ittybit video \
  -i user-video-8812.mp4 \
  -o review-preview.mp4 \
  --width 720 \
  --quality medium

Feeding the review queue

A typical webhook payload after both tasks complete:

{
  "type": "job.succeeded",
  "data": {
    "id": "task_abc123",
    "kind": "image",
    "status": "completed",
    "output": {
      "url": "https://cdn.ittybit.com/feedloop/thumb-2s.webp"
    }
  }
}

Listen for job.succeeded events, collect the thumbnail URLs and the preview MP4, then insert a row into your moderation queue with the original upload ID and the generated assets.

Moderation pipeline summary

StepKindOutputPurpose
Thumbnailsimage4 x WebP stillsVisual scan for reviewers
Transcodevideo720p MP4In-browser preview playback

Thumbnails arrive in seconds. The transcode follows. Once both are done, the upload is ready for a human decision.