Developer Guides

Real-Time Conversion Progress with Server-Sent Events

· 2 min read · Developer Guides

When a conversion takes more than a couple of seconds — large files, batch jobs, or complex transformations — your users want to know what’s happening. Server-Sent Events (SSE) give you real-time progress updates without the complexity of WebSockets.

SSE vs Polling

Polling means your client asks “are we done yet?” every N seconds. It’s simple but wasteful — most requests return “still processing.”

SSE flips the direction. The server pushes updates to the client as they happen. One persistent HTTP connection, zero wasted requests.

Feature Polling SSE
Connection overhead High (new request each time) Low (single connection)
Latency Depends on poll interval Near-instant
Server load Higher Lower
Implementation Trivial Slightly more complex
Browser support Universal Universal (EventSource API)

How KoalaPic’s SSE Works

After submitting a conversion, connect to the progress stream:

GET /api/v1/convert/{conversion_id}/stream

The server sends events as the conversion progresses:

event: progress
data: {"step": "validating", "percent": 10}

event: progress
data: {"step": "converting", "percent": 45}

event: progress
data: {"step": "compressing", "percent": 80}

event: complete
data: {"download_url": "https://koalapic.com/dl/abc123"}

JavaScript Client

The browser’s EventSource API makes SSE simple:

function trackConversion(conversionId, apiKey) {
  const url = `https://koalapic.com/api/v1/convert/${conversionId}/stream`;
  const eventSource = new EventSource(url, {
    headers: { 'Authorization': `Bearer ${apiKey}` }
  });

  eventSource.addEventListener('progress', (event) => {
    const data = JSON.parse(event.data);
    updateProgressBar(data.percent);
    updateStatusText(data.step);
  });

  eventSource.addEventListener('complete', (event) => {
    const data = JSON.parse(event.data);
    eventSource.close();
    showDownloadButton(data.download_url);
  });

  eventSource.addEventListener('error', (event) => {
    eventSource.close();
    showErrorMessage('Connection lost. Retrying...');
    // Fall back to polling
    pollForResult(conversionId, apiKey);
  });
}

Python Client

For server-side SSE consumption:

import requests

def stream_progress(conversion_id, api_key):
    url = f"https://koalapic.com/api/v1/convert/{conversion_id}/stream"
    headers = {"Authorization": f"Bearer {api_key}"}

    with requests.get(url, headers=headers, stream=True) as response:
        for line in response.iter_lines(decode_unicode=True):
            if line.startswith("data:"):
                data = json.loads(line[5:].strip())
                print(f"Progress: {data.get('percent', '?')}%")

Error Handling

SSE connections can drop due to network issues. Build in reconnection:

  1. Browser: EventSource auto-reconnects by default
  2. Custom clients: Reconnect after a short delay, use the Last-Event-ID header to resume
  3. Fallback: If SSE fails entirely, fall back to polling the conversion status endpoint

When to Use SSE vs Polling

  • Single conversions: SSE for the best UX (instant progress updates)
  • Batch jobs: SSE for overall progress, poll for individual file status
  • Simple integrations: Polling if you want minimal code

Next Steps

Enjoyed this article? Share it.

Related Posts

Send Feedback

Thank you! We'll get back to you soon.

Install KoalaPic

Add to your home screen for quick access

Cookie & Storage Preferences

We use cookies and local storage to improve your experience. Essential storage is always active for core functionality. Learn more

Essential

CSRF protection, dark mode, error tracking. Always active.

Functional

Conversion presets, UI preferences, PWA install state.

Analytics

Anonymous usage statistics to improve the service.