> ## Documentation Index
> Fetch the complete documentation index at: https://cloudinary.com/documentation/llms.txt
> Use this file to discover all available pages before exploring further.

# iOS image and video upload


Cloudinary provides support for uploading media directly from your mobile application to your Cloudinary product environment, without going through your servers first. This method allows for faster uploading and a better user experience. It also reduces load on your servers and reduces the complexity of your applications.

This page covers common usage patterns for iOS image and video upload with Cloudinary.

For details on all available upload functionality, see the [Upload](upload_images) guide, and the [upload](image_upload_api_reference#upload) method of the Upload API Reference.

For security reasons, mobile applications shouldn't contain your Cloudinary product environment credentials. You can use a [signed upload](#signed_upload), but that requires generating an authentication signature on your backend. In most cases, you will probably use [unsigned uploads](#unsigned_upload) that generally provide all the functionality you need for your mobile application, while restricting upload options that require more security.

> **INFO**: :title=Help us improve our SDK

We'd love to hear your thoughts on using our iOS SDK. Please take a moment to complete this [short survey](https://forms.gle/YyUh1gGfuWbBwaKF9). Thanks for your time!

## Upload method

The upload request is managed by the `upload` method, which accepts the file to upload as its only parameter. The file can be specified as either a `url` or `data` object. 

```swift
cloudinary.createUploader().upload(url: fileUrl)
// or
cloudinary.createUploader().upload(data: data)
```

> **NOTE**: The file is uploaded based on a background URL session. Even if your app is down, the upload will continue/resume on reconnect.

The OS attempts to initiate the upload immediately but the upload may be rescheduled depending on the system's current network, memory and cpu needs. The upload results are dispatched asynchronously and callbacks can be defined per request. 

The following simple example uploads an image called `imageFile.jpg` using the default settings:

```swift
let request = cloudinary.createUploader().upload(url: URL(string: "imageFile.jpg")!, uploadPreset: "sample_preset")
```

The result of the upload API call is a `CLDUploadResult` object that provides information about the uploaded image, including the assigned public ID of the image and its URL.

> **NOTE**: Uploading PNG files requires preprocessing with an image encoder, see [Preprocess image uploads](#preprocess_image_uploads) for more details on using the `CLDImagePreprocessChain()` object, and setting the encoder to `EncodingFormat.PNG`.

## Unsigned upload

Unsigned upload is an option for performing upload without the need to generate a signature on your backend. Unsigned upload options are controlled by an [upload preset](upload_presets): to use this feature, you first need to enable **unsigned uploading** for your Cloudinary product environment from the [Upload Presets](https://console.cloudinary.com/app/settings/upload/presets) page of the Console Settings.

An upload preset is used to define which upload options will be applied to media assets that are uploaded unsigned with that preset specified. You can edit the preset at any point in time (or create additional upload presets). 

## Signed upload

> **INFO**: Signed uploads require a [signature](signatures) which needs to be created using your api_secret. You should never expose your secret in client side code and therefore you need to generate an authentication signature on your backend. iOS signed upload with backend support should be implemented in conjunction with one of Cloudinary's backend frameworks (Java, .NET, etc). The various backend frameworks implement helpers to be used in conjunction with iOS, as well as automatically generate the authentication signature for the upload.

To implement signed uploads from an iOS device to your Cloudinary product environment you must:

1. Provide a [signature generated on your backend](authentication_signatures).
2. Include the `apiKey` [configuration parameter](cloudinary_sdks#configuration_parameters) in your front end [iOS configuration](ios_integration#setup).  
3. Add the signature and timestamp to the [upload options](#upload_options) with the `setSignature` method. 
4. Call the `signedUpload` method to upload the file.

For example, to upload an image called `imageFile.jpg`, set the publicId to `newId`, and sign the upload request:

```swift
let config = CLDConfiguration(cloudName: "xxx", apiKey:"xxx", secure: true)
let params = CLDUploadRequestParams()
  .setPublicId("newId")
var mySig = MyFunction(params)  // your own function that returns a signature generated on your backend
params.setSignature(CLDSignature(signature: mySig.signature, timestamp: mySig.timestamp))
let request = cloudinary.createUploader().signedUpload(
    url: URL(string:"imageFile.jpg")!, params: params)
```

## Upload options

You can pass an instance of `CLDUploadRequestParams`, with any extra parameters you'd want to pass, as part of the upload request. For example, to upload an image called `imageFile.jpg` using an upload preset called `samplePreset`:

```swift
let params = CLDUploadRequestParams().setPublicId("public_id")
let request = cloudinary.createUploader().upload(
  url: URL(string: "imageFile.jpg")!, uploadPreset: "sample_preset", params: params)
```

If you want to include more than one upload parameter in the request you can chain them together. For example, to upload an image called `dog.jpg`, set the publicId to `MyDog`, and add the tag `animal`:

```swift
let params = CLDUploadRequestParams()
  .setPublicId("MyDog").setTags("animal")
let request = cloudinary.createUploader().upload(
  url: URL(string: "dog.jpg")!, uploadPreset: "samplePreset", params: params)
```
> **NOTE**:
>
> For security reasons, only [this restricted set](image_upload_api_reference#unsigned_upload_parameters) of parameters can be used in an **unsigned** upload request. All other parameters you want to apply must be defined in the upload preset. For more information, see [Unsigned upload parameters](image_upload_api_reference#unsigned_upload_parameters).
> If a supported parameter is included both in the unsigned upload call and in the unsigned upload preset, the upload preset value usually takes precedence, but there are some exceptions. For details, see [Upload preset precedence](upload_presets#upload_preset_precedence).
## Chunked upload

The SDK includes the `uploadLarge` method  which offers more tolerance for network issues. This method uploads a large file to the cloud in chunks, and is required for any files that are larger than 100 MB. By default, the chunk size is set to 20 Megabytes but can be set to as low as 5 Megabytes with the `chunkSize` parameter. For example, uploading a large video file called `myVid.mp4` and setting the chunk size to 6 Megabytes:

```swift
let params = CLDUploadRequestParams()
params.setResourceType(.video)
let request = cloudinary.createUploader().uploadLarge(
  url: URL(string: "myVid.mp4")!, uploadPreset: "samplePreset", params: params, chunkSize: 6 * 1024 * 1024)
```

## Cancel an upload

If you need to cancel an upload in progress, you can use the `cancel` method:

```swift
let request = cloudinary.createUploader().signedUpload(url: fileUrl, params:params);
  ...
request.cancel();
```

## Callbacks

You can track the upload progress by passing a `progress` closure as part of the upload request, that is called periodically during the data transfer. For example:

```swift
let request = cloudinary.createUploader().upload(
    url: fileUrl, uploadPreset: "samplePreset") { progress in
      // Handle progress
} 
``` 

You can also handle the response by adding a `completionHandler` closure to be called once the upload request has finished. For example:

```swift
let request = cloudinary.createUploader().upload(
    url: fileUrl, uploadPreset: "samplePreset") { progress in
      // Handle progress
} completionHandler: { result, error in
      // Handle result
}
```

## Preprocess image uploads

You can pass an instance of `CLDImagePreprocessChain`, with any steps for preprocessing the image before uploading, as part of the upload request. The following types of processing steps are currently available: 

Step Type | Parameter | Description
---|---|----
limit | (width, height) | Scales down the image to fit within a bounding box of the given dimensions.  
rotate | (degrees) | Rotates the image by the requested degrees (clockwise).
dimensionsValidator | (minWidth, maxWidth, minHeight, maxHeight) |  Verifies the minimum and maximum dimensions for the image. Throws an error if the image does not fit within these dimensions.
customImageEncoder | (format, quality) | Saves the image using the given format (EncodingFormat.JPEG or EncodingFormat.PNG) and quality. 

For example, to limit an image to a size of 500x500 pixels, make sure that the image is at least 10x10 pixels in size, rotate the image by 90 degrees and change the format to PNG with a quality of 70:

```swift
let preprocessChain = CLDImagePreprocessChain()
    .addStep(CLDPreprocessHelpers.limit(width: 500, height: 500))
    .addStep(CLDPreprocessHelpers.rotate(degrees: 90))
    .addStep(CLDPreprocessHelpers.dimensionsValidator(minWidth: 10, maxWidth: 500, minHeight: 10, maxHeight: 500))
    .setEncoder(CLDPreprocessHelpers.customImageEncoder(format: EncodingFormat.PNG, quality: 70))
  let request = cloudinary.createUploader().upload(
      url: url, uploadPreset: "samplePreset", preprocessChain: preprocessChain) { (progress) in
        // Handle progress
  } completionHandler: { (image, error) in
        // Handle result
  }
```

> **NOTE**: In the case that you need to create your own preprocessing step you can pass a `CLDProcessStep` closure with the `addStep` method.

## Preprocess video uploads

As with images, you can also preprocess videos by transcoding them to a different size or format using an instance of the `CLDVideoPreprocessChain` as part of the upload process. This helps to handle larger video uploads. The following types of processing steps are available:

Step Type | Parameter | Description
---|---|----
setOutputFormat | format | Sets the output format for the video. Possible values: `.mov`, `.mp4` and `.m4v`. Default: `.mov`.  
setOutputDimensions | (width, height) | Sets the output dimensions for the video, the video will be scaled down to the specified size.
setCompressionPreset | preset | Applies a compression export preset to the output. See [Export presets](https://developer.apple.com/documentation/avfoundation/avassetexportsession/export_presets) for possible values. Default: `AVAssetExportPresetPassthrough`.
dimensionsValidator | (minWidth, maxWidth, minHeight, maxHeight) |  Verifies the minimum and maximum dimensions for the video. Throws an error if the video does not fit within these dimensions.

For example, to limit a video to a size of 500x500 pixels, make sure that the video is at least 250x250 pixels in size, change the format to MP4 and use the `AVAssetExportPresetHighestQuality` compression preset:

```swift
let params = CLDUploadRequestParams()
params.setResourceType(.video)
let preset = AVAssetExportPresetHighestQuality
let preprocessChain = CLDVideoPreprocessChain()
    .addStep(CLDVideoPreprocessHelpers.setOutputDimensions(dimensions: CGSize(width: 500, height: 500)))
    .addStep(CLDVideoPreprocessHelpers.dimensionsValidator(minWidth: 250, maxWidth: 500, minHeight: 250, maxHeight: 500))
    .addStep(CLDVideoPreprocessHelpers.setOutputFormat(format: .mp4))
    .addStep(CLDVideoPreprocessHelpers.setCompressionPreset(preset: preset))
  let request = cloudinary.createUploader().upload(
      url: url, uploadPreset: "samplePreset", params: params, preprocessChain: preprocessChain) { (progress) in
        // Handle progress
  } completionHandler: { (video, error) in
        // Handle result
  }
```

## iOS upload widget

The iOS upload widget offers an interactive user interface that enables your users to edit and then upload files to your Cloudinary product environment. The widget, requiring just a couple lines of code to integrate, eliminates the need to develop certain in-house interactive media upload capabilities. Currently, the widget provides an interactive cropping capability and allows rotation of an image before uploading.
You call the upload widget by instantiating a new `CLDUploaderWidget` and calling its `presentWidget()` method with the calling ViewController (using `self` in this example):
 
```swift
let uploadWidget = CLDUploaderWidget(
  cloudinary: myCldInstance, 
  configuration: nil, 
  images: nil, 
  delegate: nil)
 
uploadWidget.presentWidget(from: self)
```

### iOS upload widget options

The upload widget takes five parameters that control its basic behavior:

Name | Type | Nullable | Description
---|---|---|---
cloudinary |CLDCloudinary|No|The Cloudinary instance used for uploading.
configuration|CLDWidgetConfiguration|yes|See the table [below](#upload_widget_configuration).
images|UIImage Array|yes|Images to preload into the widget.
videos|AVPlayerItem Array|yes|Videos to preload into the widget
delegate|CLDUploaderWidgetDelegate|yes|Delegate for upload widgets [callbacks](#ios_upload_widget_callbacks). This is used to get notified when the widget is closed or canceled.
 
> **NOTE**: If both images and videos are empty, the widget will automatically launch the device's file picker.
The configuration parameter allows for some more advanced customization options, by creating a new instance and sending it to the widget's constructor.

The configuration object takes the following parameters:

Name|Type |Default |Description
---|---|---|---
allowRotate|Bool|true|Whether to allow rotation of images in the widget
initialAspectLockState|AspectRatioLockState (enum)|enabledAndOff|Sets up the mode of the aspect ratio lock.
uploadType|CLDUploadType (enum: signed or unsigned+preset)|signed|Signed upload or unsigned (also provide the preset).
 
 
A code example with more options:

```swift
let myConfig = CLDWidgetConfiguration(
  allowRotate: false, 
  initialAspectLockState: .disabled, 
  uploadType: CLDUploadType(signed: false, preset: "ios_sample"))
        
uploaderWidget = CLDUploaderWidget(
  cloudinary: myCldInstance,
  configuration: myConfig, 
  images: initialImageList,
  videos: null, 
  delegate: self)
 
uploaderWidget.presentWidget(from: self)
```

### iOS upload widget callbacks

A class implementing the `CLDUploaderWidgetDelegate` is used to receive callbacks from the widget. It's common practice to have the calling view controller implement that protocol and send `self` to the widget's constructor (such as in the example above).

The protocol has three methods:

1. `func uploadWidget(_ widget: CLDUploaderWidget, willCall uploadRequests: [CLDUploadRequest])`This is the main callback - it informs the caller that the uploads are starting, passing on the list of references to active uploads. This allows the caller to set up callbacks per request (if required), track progress and cancel the requests. This is the same request object returned from the regular iOS upload methods.

2. `func widgetDidCancel(_ widget: CLDUploaderWidget)`Notifies the caller that the widget was canceled.

3. `uploadWidgetDidDismiss`Notifies the caller that the widget was dismissed and is no longer visible.

Add your own callback code by calling `uploadRequests` within a controller that implements the `CLDUploaderWidgetDelegate` protocol:

```swift
class WidgetSettingsViewController: CLDUploaderWidgetDelegate {
    func uploadWidget(_ widget: CLDUploaderWidget, willCall uploadRequests: [CLDUploadRequest]) {
       // your code here to handle the upload progress or cancel the upload itself
       // for example to track the upload response of the second upload:
      uploadRequests[1].response( { response, error in
        // Handle response
      } )
       // for example to cancel the first upload:
      uploadRequests[0].cancel()
    }
    func widgetDidCancel(_ widget: CLDUploaderWidget) {
       // your code here in the case that the user closes the UI before the upload starts
    }
    func uploadWidgetDidDismiss() {
      // your code here for when the widget is dismissed
    }
  }
```
