Skip to main content

Designing APIs for Mobile: Bandwidth, Latency, and Offline

·APIScout Team
mobile apiapi designoffline firstbandwidthapi architecture

Designing APIs for Mobile: Bandwidth, Latency, and Offline

Mobile apps operate under constraints desktop apps don't face: limited bandwidth, high latency, unreliable connections, battery consumption, and offline usage. APIs designed for desktop/server consumers often perform poorly on mobile. Here's how to design APIs that work well in the mobile context.

The Mobile Constraints

ConstraintImpactAPI Design Response
High latency (100-500ms)Every round trip hurts UXReduce number of requests
Limited bandwidthLarge payloads waste dataMinimize payload size
Unreliable connectionRequests fail mid-flightIdempotency, retry safety
Offline periodsApp must work without networkOffline-first, sync protocols
BatteryNetwork calls drain batteryBatch requests, reduce polling

1. Reduce Round Trips

Aggregate Endpoints

Instead of three separate requests for a screen:

❌ GET /api/user/profile
❌ GET /api/user/notifications
❌ GET /api/user/feed

Provide a single endpoint:

✅ GET /api/home?include=profile,notifications,feed

GraphQL for Mobile

GraphQL's single-endpoint, query-what-you-need approach is ideal for mobile:

query HomeScreen {
  profile { name avatar }
  notifications(first: 5) { title read }
  feed(first: 20) { id title thumbnail }
}

One request. Only the fields the mobile UI needs. No over-fetching.

2. Minimize Payload Size

Sparse Fields

Let clients specify which fields to return:

GET /api/products?fields=id,title,price,thumbnail

A product might have 50 fields. The list view only needs 4.

Pagination Defaults

Mobile lists show 10-20 items at a time. Default limit should match:

GET /api/feed?limit=20

Don't send 100 items when the screen shows 10.

Compressed Responses

Enable gzip/brotli compression. JSON compresses well (60-80% reduction):

Accept-Encoding: gzip, br
Content-Encoding: gzip

Image Optimization

Don't send full-resolution images when the mobile screen needs thumbnails:

{
  "images": {
    "thumbnail": "https://cdn.example.com/img/123_100x100.webp",
    "medium": "https://cdn.example.com/img/123_400x400.webp",
    "full": "https://cdn.example.com/img/123_1200x1200.webp"
  }
}

3. Handle Unreliable Connections

Idempotency Keys

Mobile users may retry when they don't see a response. Every mutating request should support idempotency keys to prevent duplicates.

Timeout and Retry

Set aggressive timeouts (10-15 seconds). Implement automatic retry with exponential backoff for 5xx and network errors. Never retry 4xx errors.

Optimistic Updates

Update the UI immediately before the API confirms. If the API call fails, revert the UI change. This makes the app feel instant even on slow connections.

4. Offline-First

Local Cache

Cache API responses locally (SQLite, Realm, Core Data). Serve from cache when offline. Sync when connection returns.

Sync Protocol

When the app comes online, sync changes:

POST /api/sync
{
  "last_sync": "2026-03-08T12:00:00Z",
  "changes": [
    {"type": "create", "resource": "task", "data": {...}},
    {"type": "update", "resource": "task", "id": "123", "data": {...}}
  ]
}

Conflict Resolution

When offline edits conflict with server state, the API needs a strategy:

  • Last write wins — simplest, sometimes loses data
  • Server wins — safe, may frustrate users
  • Client wins — risky, may overwrite others' changes
  • Merge — complex, best UX

5. Push Over Pull

Push Notifications Instead of Polling

Don't poll for new data. Use push notifications (FCM/APNs) to notify the app when new data is available. The app then fetches the specific new data.

Server-Sent Events or WebSocket

For real-time data (chat, live updates), use SSE or WebSocket instead of frequent polling. One persistent connection vs hundreds of polling requests.

6. Mobile-Specific API Patterns

App Version Header

X-App-Version: 2.5.3
X-Platform: iOS

Use app version headers to handle backward compatibility. Different app versions may need different response formats.

Feature Flags

Return feature flags in a lightweight endpoint so the app can show/hide features without an app update:

GET /api/config
{
  "features": {
    "dark_mode": true,
    "new_checkout": false
  },
  "min_version": "2.3.0"
}

Force Update

Include minimum supported version. If the app version is below minimum, show an update prompt:

{
  "min_version": "2.3.0",
  "update_url": "https://apps.apple.com/..."
}

Designing mobile APIs? Explore API design patterns and best practices on APIScout — architecture guides, comparisons, and developer resources.

Comments