> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://fastpix.com/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://fastpix.com/docs/_mcp/server.

# Set up resumable uploads for Flutter

The FastPix [Flutter Resumable Uploads](https://pub.dev/packages/fastpix_resumable_uploader) SDK helps you efficiently upload large files from Flutter apps by splitting them into chunks and also gives you the ability to pause and resume your uploads.

\


#### How resumable uploads work through chunking

\


Resumable uploads can be effectively handled through a technique called **chunking**. This method involves breaking down large files into smaller, more manageable pieces, or "chunks." Here's how chunking works:

1. **Divide the file**: Large files are split into smaller, manageable chunks (e.g., 16 MB by default).
2. **Upload individually**: Each chunk is uploaded separately. If a chunk fails, only that specific chunk needs to be re-uploaded.
3. **Resume capability**: If the upload is interrupted, you can resume from the last successfully uploaded chunk instead of starting over.

\


This approach is important because:

* **It reduces the risk**: Uploading smaller chunks minimizes the risk of failure. If a chunk fails to upload due to network issues, only that specific chunk needs to be re-uploaded, not the entire file.
* **Improves performance**: Smaller chunks can be uploaded more quickly and efficiently, especially on slower connections, as they require less time to transfer.
* **Easier management**: Chunking allows for better tracking of upload progress, making it easier to implement features like pause and resume.

\
\


## Step 1: Install the Flutter SDK

\


**Add the dependency to your`pubspec.yaml`**

Add FastPix’s Flutter library to the dependencies block of your `pubspec.yaml` file.

```yaml
dependencies:
flutter:
sdk: flutter
fastpix_resumable_uploader: ^1.0.0
```

\


**Install dependencies**\
Run the following command to install the dependencies:

```shell
flutter pub get
```

\


## Step 2: Create an upload URL

In order to upload a video, you will need a signed upload URL.

To get this signed URL, you'll need a valid **Access Token** and **Secret Key**. See the Basic [Authentication Guide](/getting-started/activate-your-account#access-token-permissions) for details on retrieving these credentials.

Once you have your credentials, use the [Upload media from device](/video-on-demand-api/upload-and-import-videos/direct-upload-video-media#/) API to generate a signed URL for uploading media. After fetching the the signed URL you can continue with integrating the SDK into your application.

The example below gives you an idea about how to get the signed URL using the [upload media from device](/video-on-demand-api/upload-and-import-videos/direct-upload-video-media) API. You can use the example directly or also refer to our [upload videos directly](/upload-videos/upload-videos-from-device) guide.

\


**`Dart`**

```java Dart
import  'dart:convert';
import  'dart:io';
import  'package:http/http.dart'  as http;

Future<String> getSignedUrl() async {
    final client = http.Client();
    // Construct JSON body
    final requestBody = jsonEncode({
        "corsOrigin": "*",
        "pushMediaSettings": {
            "metadata": {
            "key1": "value1"
            },
        "accessPolicy": "public",
        "maxResolution": "1080p",
        "mediaQuality": "standard"
        }
    });
    // Create Authorization header
    final credentials = "$tokenId:$secretKey";
    final auth = "Basic ${base64Encode(utf8.encode(credentials))}";
    try {
        final response = await client.post(
            Uri.parse('https://api.fastpix.com/v1/on-demand/uploads'),
            headers: {
            'Authorization': auth,
            'Content-Type': 'application/json',
            },
            body: requestBody,
        );
        if (response.statusCode == 200) {
            final data = jsonDecode(response.body);
            return data['signedUrl']; // Return the signed URL
        } else {
            throw  Exception('Failed to get signed URL: ${response.statusCode}');
        }
    } finally {
        client.close();
    }
}
```

\


## Step 3: Start your upload

The Flutter SDK provides a builder pattern for easy configuration and initialization:

**`Dart`**

```java Dart
import  'dart:io';
import  'package:fastpix_resumable_uploader/fastpix_resumable_uploader.dart';

Future<void> uploadVideo() async {
    final file = File('/path/to/your/video.mp4');
    final signedUrl = await getSignedUrl(); // Get signed URL from Step 2
    final uploadService = FlutterResumableUploads.builder()
        .file(file)
        .signedUrl(signedUrl)
        .chunkSize(16 * 1024 * 1024) // 16MB chunks
        .maxRetries(3)
        .retryDelay(Duration(milliseconds: 2000))
        .onProgress((progress) {
            print('Upload progress: ${progress.uploadPercentage}%');
            print('Current chunk: ${progress.currentChunkIndex}/${progress.totalChunks}');
        })
        .onError((error) {
            print('Upload error: ${error.message}');
        })
        .build();
    await uploadService.uploadVideo();
}
```

\


### Builder configuration options

| Parameter     | Type     | Default   | Description                              |
| ------------- | -------- | --------- | ---------------------------------------- |
| `file`        | File     | Required  | The video file to upload                 |
| `signedUrl`   | String   | Required  | The signed URL for upload                |
| `chunkSize`   | int      | 16MB      | Size of each chunk in bytes              |
| `maxFileSize` | int?     | Optional  | Maximum allowed file size                |
| `maxRetries`  | int      | 3         | Maximum retry attempts for failed chunks |
| `retryDelay`  | Duration | 2 seconds | Delay between retry attempts             |
| `onProgress`  | Function | Optional  | Progress callback function               |
| `onError`     | Function | Optional  | Error callback function                  |
| `onPause`     | Function | Optional  | Pause callback function                  |
| `onAbort`     | Function | Optional  | Abort callback function                  |

\
\


## Step 4: Monitor upload events

The SDK provides comprehensive callback methods to monitor upload progress and handle various events:

**`Dart`**

```java Dart
FlutterResumableUploads.builder()
    .file(file)
    .signedUrl(signedUrl)
    .onProgress((progress) {
    // Called periodically to report upload progress
        print('Upload progress: ${progress.uploadPercentage}%');
        print('Current chunk: ${progress.currentChunkIndex}/${progress.totalChunks}');
        print('Status: ${progress.status}');
    })
    .onError((error) {
        // Called when an error occurs during upload
        print('Upload error: ${error.message}');
        print('Error code: ${error.code}');
    })
    .onPause(() {
        // Called when the upload is paused
        print('Upload paused');
    })
    .onAbort(() {
        // Called when the upload is aborted
        print('Upload aborted');
    })
    .build();
```

\


**Progress model**\
The progress callback provides a ProgressModel with the following properties:

* `uploadPercentage`: Progress percentage (0.0 - 100.0)
* `currentChunkIndex`: Current chunk being uploaded
* `totalChunks`: Total number of chunks
* `status`: Current upload status (e.g., “splitting\_chunks”, “uploading\_chunks”, “completed”)
* `fileSize`: Total file size in bytes
* `uploadedBytes`: Number of bytes uploaded so far

\
\


## Step 5: Manage video uploads

You can control the upload lifecycle with the following methods:

\


### Pause an upload

**`Dart`**

```java Dart
uploadService.pauseUpload();
```

\


### Resume an upload

**`Dart`**

```java Dart
uploadService.resumeUpload();
```

\


### Abort an upload

**`Dart`**

```java Dart
uploadService.abortUpload();
```

\


### Check upload status

**`Dart`**

```java Dart
final isPaused = uploadService.isPaused;
final isCompleted = uploadService.isCompleted;
final isAborted = uploadService.isAborted;
```

\
\


## Detailed usage example

The following example gives an overview of integrating the FastPix [Flutter Uploads SDK](https://pub.dev/packages/fastpix_resumable_uploader) into your project, enabling you to build a fully customized upload interface:

\


**`Dart`**

```java Dart
import  'dart:io';
import  'package:flutter/material.dart';
import  'package:fastpix_resumable_uploader/fastpix_resumable_uploader.dart';

class  UploadScreen  extends  StatefulWidget {
    @override
    _UploadScreenState createState() => _UploadScreenState();
}

class _UploadScreenState extends  State<UploadScreen> {
    FlutterResumableUploads? _uploadService;
    double _progress = 0.0;
    String _status = 'Ready to upload';
    bool _isUploading = false;
    bool _isPaused = false;

    @override

    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text('Video Upload'),
            ),
            body: Padding(
                padding: EdgeInsets.all(16.0),
                child: Column(
                    children: [
                        // Progress indicator
                        LinearProgressIndicator(
                            value: _progress / 100.0,
                            backgroundColor: Colors.grey[300],
                            valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
                        ),
                        SizedBox(height: 16),
                        // Status text
                        Text(
                            _status,    
                            style: TextStyle(fontSize: 16),
                        ),
                        SizedBox(height: 24),
                        ElevatedButton(
                            onPressed: _isUploading ? null : _startUpload,
                            child: Text('Start Upload'),
                        ),
                        SizedBox(height: 16),
        // Pause/Resume button
                    if (_isUploading)
                        ElevatedButton(
                            onPressed: _isPaused ? _resumeUpload : _pauseUpload,
                            child: Text(_isPaused ? 'Resume' : 'Pause'),
                        ),
                        SizedBox(height: 16),
                        // Abort button
                        if (_isUploading)
                        ElevatedButton(
                            onPressed: _abortUpload,
                            style: ElevatedButton.styleFrom(
                                backgroundColor: Colors.red,
                            ),
                            child: Text('Abort Upload'),
                        ),
                    ],
                ),
            ),
        );
    }

    Future<void> _startUpload() async {
        try {
            final file = File('/path/to/your/video.mp4');
            final signedUrl = await getSignedUrl(); // Implement this method
            setState(() {
                _isUploading = true;
                _status = 'Initializing upload...';
            });
            _uploadService = FlutterResumableUploads.builder()
                .file(file)
                .signedUrl(signedUrl)
                .chunkSize(16 * 1024 * 1024) // 16MB chunks
                .maxRetries(3)
                .retryDelay(Duration(milliseconds: 2000))
                .onProgress((progress) {
                    setState(() {
                        _progress = progress.uploadPercentage;
                        _status = 'Uploading: ${progress.currentChunkIndex}/${progress.totalChunks} chunks';
                    });
                })
                .onError((error) {
                    setState(() {
                        _status = 'Error: ${error.message}';
                        _isUploading = false;
                    });
                })
                .onPause(() {
                    setState(() {
                        _isPaused = true;
                        _status = 'Upload paused';
                    });
                })
                .build();
            await _uploadService!.uploadVideo();
            setState(() {
                _status = 'Upload completed successfully!';
                _isUploading = false;
                _progress = 100.0;
            });
        } catch (e) {
            setState(() {
                _status = 'Error: $e';
                _isUploading = false;
            });
        }
    }

    void _pauseUpload() {
        _uploadService?.pauseUpload();
    }

    void _resumeUpload() {
        _uploadService?.resumeUpload();
        setState(() {
            _isPaused = false;
            _status = 'Uploading...';
        });
    }

    void _abortUpload() {
        _uploadService?.abortUpload();
        setState(() {
            _isUploading = false;
            _isPaused = false;
            _status = 'Upload aborted';
            _progress = 0.0;
        });
    }

    @override
    void dispose() {
        _uploadService?.abortUpload();
        super.dispose();
    }
}
```

\


## Features

\


**Core features**

* **Chunking**: Files are automatically split into chunks (default chunk size is 16MB).
* **Pause and resume**: Allows temporarily pausing the upload and resuming after a while.
* **Retry**: Uploads might fail due to temporary network failures. Individual chunks are retried with exponential backoff to recover automatically from such failures.
* **Lifecycle event listeners**: Provides real-time feedback through various upload lifecycle events.
* **Error handling**: Comprehensive error management to notify users of issues during uploads.
* **Customizability**: Options to customize chunk size and retry attempts.

\


**Advanced features**

* **Network health monitoring**: Automatically detects network connectivity changes and handles offline scenarios.
* **Upload lock management**: Prevents multiple concurrent uploads from the same service instance.
* **Progress tracking**: Detailed progress reporting with chunk-level information.
* **File validation**: Built-in file size and format validation.
* **Memory efficient**: Streams file chunks without loading the entire file into memory.

\


> **BEST PRACTICES**
>
> **Chunk Size**: Use appropriate chunk sizes based on your target platform and network conditions. 16MB is a good default for most scenarios.
>
> **Error Handling**: Always implement proper error handling to provide meaningful feedback to users.\
> Progress Updates: Use progress callbacks to update your UI and keep users informed about upload status.
>
> **Network Monitoring**: The SDK automatically handles network connectivity changes, but you may want to add additional network monitoring for better UX.
>
> **Memory Management**: For very large files, consider implementing additional memory management strategies.
>
> **Retry Configuration**: Adjust retry settings based on your network environment and requirements.

\
\


## Troubleshooting common issues

#### Upload fails immediately

Check if the signed URL is valid and not expired.

#### Chunks fail to upload

Verify network connectivity and adjust retry settings.

#### Memory issues with large files

The SDK handles memory efficiently, but ensure your app has sufficient memory allocation.

#### Progress not updating

Make sure you’re properly implementing the progress callback.

\


> **DEBUG INFORMATION**
>
> Enable debug logging to get detailed information about upload operations.
>
> * The SDK automatically logs debug information when running in debug mode.
> * Check the console output for detailed upload information

\


For more information and support, [contact us](https://www.fastpix.io/technical-support).

\


## Changelog

All notable changes to this project are documented in this file.

### 2.0.0

#### Spec correctness — GCS resumable protocol compliance

* **Parse the `Range:` response header on 308 responses.** The client now
  resyncs its cursor to the byte offset GCS actually committed instead of
  blindly advancing to the end of the chunk it sent. Fixes silent data
  corruption on flaky networks where the server partially commits a chunk
  before returning 308.
* **Status-query path (`Content-Range: bytes */<total>`).** After any
  transient failure / timeout / network loss / signed-URL refresh, the SDK
  now asks GCS for its true cursor before re-uploading. Available as
  `_resyncCursorFromServer()` internally and via `refreshSignedUrl(...)`
  publicly.
* **Any 2xx is now terminal success.** Previously only HTTP 200 finalized
  the upload; 201 / 204 fell through to the retry path.
* **Empty trailing chunk guard.** When the local cursor reaches EOF but no
  terminal 2xx has been observed, the SDK queries the server rather than
  PUT-ing a zero-byte (and inverted-Range) request.

#### Retry policy

* **Real exponential backoff with jitter.** `2s, 4s, 8s, 16s, 30s (cap)`
  with ±25% jitter. Previously linear (`2s, 4s, 6s…`) with no jitter —
  no longer prone to thundering-herd on shared-backend incidents.
* **HTTP-status-aware retry classification.** 4xx (other than 408/429) is
  no longer retried. 408/429/5xx are retried; everything else surfaces as
  a permanent failure.
* **Stop swallowing timeouts and `DioExceptionType.unknown`.** Connection
  errors, send/receive timeouts, and unknown transport faults are now
  classified as transient and routed through the retry path.
* **Retry timers are tracked and cancelled** on `dispose()`, `abortUpload()`,
  and `reset()`. Stray retry callbacks no longer fire into stale state.
* **`DioExceptionType.badCertificate`** is treated as permanent (cert
  pinning / MITM situations should not be retried).

#### Concurrency / state

* **Pause and abort no longer surface through the error stream.**
  Previously the SDK emitted `UploadError('Upload Paused')` and
  `UploadError('Upload Aborted')` via `onError`, which led consumers to
  treat user-initiated pause as a failure (and disable the Resume button).
  Pause and abort are now communicated only through the dedicated
  `onPause` / `onAbort` callbacks and the progress event with the
  appropriate `UploadStatus`.
* **De-singletoned `VideoUploadProgress`.** Was a process-wide static class
  whose callbacks were overwritten by every new uploader — two concurrent
  uploads in the same app would cross-wire their callbacks. Now per-instance.
* **De-singletoned `VideoUploadRetry`.** Per-instance retry controller
  owns its own pending timer.
* **First-network-event swallow fixed.** The `_isFirstTime` flag no
  longer drops the first connectivity event, so an upload kicked off while
  offline can be auto-resumed when the network returns.

#### API surface (breaking changes — see "Migration" below)

* **`uploadVideo()` now returns a `Future<void>` that actually resolves
  when the upload finalizes** (or rejects with `UploadError` on permanent
  failure / abort). Previously the future resolved immediately after the
  first chunk was scheduled.
* **`progressStream` and `errorStream`** — broadcast streams on the
  uploader for callers that want more than one listener or prefer streams
  over callbacks. The legacy `onProgress` / `onError` callbacks still work.
* **`isUploading()` now honors terminal failure state** — returns false
  after a permanent failure instead of staying true forever.
* **`onUrlRefresh: Future<String> Function()`** — builder hook called
  automatically when the SDK detects an expired signed URL (HTTP
  401 / 403 / 410). Mint a fresh URL and the upload resumes from the
  server's committed cursor against the new URL.
* **`refreshSignedUrl(String)`** — manual / proactive URL replacement on
  the uploader.
* **`.observeAppLifecycle()`** — opt-in builder flag. Attaches a
  `WidgetsBindingObserver` that auto-pauses on background and resumes
  on foreground. Does NOT enable true background uploads (that needs
  platform-level integration), but leaves the resumable session in a
  clean state for when the user returns.
* Builder default `maxRetries` reconciled with the uploader default (both
  now 5). Removed the dead `_builderMaxRetries` field.

#### Memory / performance

* **Killed the double-copy in `VideoUploadChunker.readFileChunk`.**
  `Uint8List.fromList(raf.read(...))` is replaced with the direct
  `raf.read(...)` return — saves a 16 MB copy per chunk.
* **`Uint8List.sublistView` in the progress stream** in place of
  `sublist`. For a 4 GB upload that's \~1M fewer heap allocations.

#### Tests

* 32 unit tests covering chunker math, file-chunk read edge cases,
  exponential-backoff math (doubling, cap, jitter bounds, never-negative),
  GCS `Range:` header parsing, and HTTP-status classification
  (200 / 201 / 204 / 308 / 308-with-Range / 400 / 403 / 408 / 429 / 500).

#### Migration from 1.x

```diff
- final uploader = FlutterResumableUploads.builder()
-     .file(file)
-     .signedUrl(url)
-     .onProgress((p) => ...)
-     .build();
- // upload was fire-and-forget; this returned immediately
- await uploader.uploadVideo();
+ final uploader = FlutterResumableUploads.builder()
+     .file(file)
+     .signedUrl(url)
+     .onProgress((p) => ...)
+     .onUrlRefresh(() => myBackend.mintSignedUrl())  // optional
+     .observeAppLifecycle()                          // optional
+     .build();
+ try {
+   // now actually awaits completion
+   await uploader.uploadVideo();
+ } on UploadError catch (e) {
+   // permanent failure / abort / exhausted retries
+ }
```

* If your code relied on the static `VideoUploadProgress.emitProgress(...)`
  / `VideoUploadProgress.setupCallbacks(...)` access path, switch to
  per-instance methods on `FlutterResumableUploads` (or use the new
  `progressStream` / `errorStream`).

### 1.0.1

#### Documentation & Homepage URL Update

* Updated `homepage` in `pubspec.yaml` from `https://www.fastpix.io/` to `https://www.fastpix.com/`.
* Updated documentation links in `README.md` (Basic Authentication, Upload media from device) from `docs.fastpix.io` to `docs.fastpix.com`.
* Updated documentation link in the GitHub issue template (`.github/ISSUE_TEMPLATE/question_support.md`) from `docs.fastpix.io` to `docs.fastpix.com`.

### 1.0.0

#### Initial Release - Flutter Resumable Uploads SDK

A robust Flutter package for uploading large video and audio files with enterprise-grade features.

##### Core Features

* **Chunked Upload System**: Automatically splits large files into configurable chunks (default 16MB) for reliable uploads
* **Resumable Uploads**: Pause and resume functionality with state persistence across app sessions
* **Network Resilience**: Automatic retry mechanism with configurable retry attempts and delays
* **Advanced Chunk-Level Retry Tracking**: Individual retry tracking per chunk to prevent app sluggishness
* **Real-time Progress Tracking**: Detailed progress updates with chunk-level information and percentage completion
* **Network Monitoring**: Automatic detection of network connectivity changes with smart resume logic
* **Comprehensive Error Handling**: Detailed error reporting with specific error codes and messages
* **Advanced Logging System**: Configurable logging with multiple levels (DEBUG, INFO, WARNING, ERROR)

##### Architecture & Design

* **Builder Pattern**: Clean, fluent API for easy configuration and setup
* **State Management**: Robust state tracking for upload progress, network status, and retry attempts
* **Modular Design**: Well-organized codebase with separate modules for core, network, models, and utilities
* **Memory Efficient**: Proper resource management with dispose and reset capabilities
* **Thread Safe**: Upload lock mechanism to prevent concurrent upload conflicts

##### Technical Capabilities

* **File Validation**: Comprehensive file size and format validation
* **Signed URL Support**: Secure uploads using pre-authenticated URLs
* **HTTP Status Handling**: Proper handling of 308 (Partial Content) and 200 (Complete) responses
* **Cancel Token Integration**: Dio-based cancellation for clean upload termination
* **Upload Statistics**: Detailed logging of upload metrics and retry statistics
* **Network Health Monitoring**: Real-time network connectivity monitoring using connectivity\_plus

##### Developer Experience

* **Fluent API**: Easy-to-use builder pattern for configuration
* **Callback System**: Comprehensive callback support for progress, errors, pause, and abort events
* **Debug Information**: Rich debugging capabilities with detailed state information
* **Error Recovery**: Intelligent error handling with automatic retry and manual recovery options
* **Documentation**: Comprehensive documentation with usage examples and best practices

##### Configuration Options

* **Chunk Size**: Configurable chunk size (default: 16MB)
* **Retry Settings**: Customizable retry attempts and delay intervals
* **File Size Limits**: Optional maximum file size validation
* **Logging Control**: Enable/disable logging with custom log levels and tags
* **Network Timeouts**: Configurable network timeout settings

##### Security & Reliability

* **Secure Uploads**: Signed URL-based authentication
* **Data Integrity**: Proper chunk validation and error checking
* **Resource Management**: Automatic cleanup and memory management
* **State Persistence**: Upload state tracking for reliable resume functionality

##### Dependencies

* **dio**: ^5.8.0+1 - HTTP client for network operations
* **connectivity\_plus**: ^6.1.4 - Network connectivity monitoring
* **internet\_connection\_checker**: ^3.0.1 - Internet connection validation

##### Use Cases

* Large video file uploads in mobile applications
* Audio file uploads with progress tracking
* Media uploads requiring pause/resume functionality
* Applications requiring network resilience
* Enterprise applications needing detailed upload analytics

\