> ## 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.

# Upload


Using Cloudinary's upload capabilities, you can upload media assets in bulk with a variety of options for customizing how they will be uploaded.

When you upload to Cloudinary, your asset isn't only stored, but Cloudinary also automatically analyzes and saves important data about each asset, such as format, size, resolution, prominent colors, etc. This data is also automatically indexed to enable searching on those attributes.  

Cloudinary provides a secure and comprehensive API for easily uploading media files from server-side code, directly from the browser or from a mobile application. For full details, see the [Upload API reference](image_upload_api_reference). When needed, you can also use the API to perform unsigned uploads, but with a limited set of available upload parameters as a security precaution.

> **TIP**: :title=New to Cloudinary?

This guide provides an in-depth overview of Cloudinary's Upload API capabilities. To get started with the basics of uploading (and more) in 5 minutes or less, we recommend you first run through one of our [backend SDK quick starts](sdk_quickstarts). 

Each quick start gives you the code to configure your SDK, run your first upload, and then perform a few other common Cloudinary operations, all using your favorite programming language or framework. 

If you haven't moved over your existing assets to Cloudinary yet, you may also want to check out our [Migration guide](migration).

Clara Denari's Mystery Game: The Case of the Sapphire Earrings

Clara found sapphire earrings in her backyard, but her neighbor Mrs. Patterson claims they're a family heirloom and has an old photo to prove it. The problem? The photo is too blurry to tell if the earrings match.
Help Clara upload a restored version using Cloudinary's generative restore effect and find out if Mrs. Patterson's story checks out!

Play the Game

## Upload with Cloudinary MCP in Cursor

The **Asset Management MCP server** enables AI agents to upload images, videos, and raw files to your product environment and generate code that integrates Cloudinary functionality into your applications.

**Learn more**: [Cloudinary MCP servers and LLM tools](cloudinary_llm_mcp)

Use this link to add the Asset Management MCP server to Cursor. Make sure to update your **cloud name**, **API key**, and **API secret** in **Cursor Settings -> MCP Tools**.

  
    
    Add Asset Management MCP
    
    Use this server to perform uploads, to delete, rename, or modify assets, or to manage asset folders and tags.  

  
      
  

> **TIP**: :title=Use the VS Code Extension
You can also upload assets directly from your IDE using the [Cloudinary VS Code Extension](cloudinary_vscode_extension). This eliminates context-switching between your code editor and browser, helping you stay focused on development.

## Quick examples

**Example 1**: Upload the local `hat.jpg` image, and use the filename to set the [public ID](upload_parameters#public_id).

```multi
|ruby 
Cloudinary::Uploader.upload("hat.jpg", 
  use_filename: true)

|php_2
use Cloudinary\Api\Upload\UploadApi;

(new UploadApi())->upload('hat.jpg', [
  'use_filename' => true]);
    
  
|python
cloudinary.uploader.upload("hat.jpg", 
  use_filename = True)

|nodejs
cloudinary.v2.uploader
.upload("hat.jpg", { 
  use_filename: true})
.then(result=>console.log(result));
  
|java
Map params = ObjectUtils.asMap(
    "use_filename", true);
Map uploadResult = cloudinary.uploader().upload(new File("hat.jpg"), params);

|csharp
var uploadParams = new ImageUploadParams()
    {
        File = new FileDescription(@"hat.jpg"),   
        UseFilename = true};
var uploadResult = cloudinary.Upload(uploadParams);

|go
resp, err := cld.Upload.Upload(ctx, "hat.jpg", uploader.UploadParams{
  UseFilename: api.Bool(true)
})

|android
MediaManager.get().upload("hat.jpg")
   .option("use_filename", "true")
   .dispatch();

let params = CLDUploadRequestParams()
  .setUseFilename(true)
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:"hat.jpg")!, params: params)

|curl
curl https://api.cloudinary.com/v1_1/demo/image/upload -X POST --data 'file=https://www.example.com/hat.jpg&use_filename=true&timestamp=173719931&api_key=436464676&signature=a788d68f86a6f868af'
```

**Example 2**: 

* Upload a remote image from wikipedia
* Set the [public ID](upload_parameters#public_id) as "wiki_shirt"
* Request [color and quality analysis](semantic_data_extraction)
* Run the [Google Auto Tagging](google_auto_tagging_addon#adding_resource_tags_to_images) add-on 
* Automatically add the detected categories as tags to the asset

```multi
|ruby 
Cloudinary::Uploader.upload("https://upload.wikimedia.org/wikipedia/commons/0/01/Charvet_shirt.jpg", 
  public_id: "wiki_shirt", 
  quality_analysis: true,
  colors: true,
  categorization: "google_tagging",
  auto_tagging: 0.8)

|php_2
use Cloudinary\Api\Upload\UploadApi;

(new UploadApi())->upload('https://upload.wikimedia.org/wikipedia/commons/0/01/Charvet_shirt.jpg', [
  'public_id' => 'wiki_shirt', 
  'quality_analysis' => true,  
  'colors' => true, 
  'categorization' => 'google_tagging', 
  'auto_tagging' => 0.8]);
    
  
|python
cloudinary.uploader.upload("https://upload.wikimedia.org/wikipedia/commons/0/01/Charvet_shirt.jpg", 
  public_id = "wiki_shirt",
  quality_analysis = True, 
  colors = True,  
  categorization = "google_tagging",
  auto_tagging = 0.8)

|nodejs
cloudinary.v2.uploader
.upload("https://upload.wikimedia.org/wikipedia/commons/0/01/Charvet_shirt.jpg", { 
  public_id: "wiki_shirt",
  quality_analysis: true, 
  colors: true, 
  categorization: "google_tagging",
  auto_tagging: 0.8})
.then(result=>console.log(result));
  
|java
Map params = ObjectUtils.asMap(
    "public_id", "wiki_shirt", 
    "quality_analysis", true,
    "colors", true,
    "categorization", "google_tagging", 
    "auto_tagging", 0.8);
Map uploadResult = cloudinary.uploader().upload(new File("https://upload.wikimedia.org/wikipedia/commons/0/01/charvet_shirt.jpg"), params);

|csharp
var uploadParams = new ImageUploadParams()
    {
        File = new FileDescription(@"https://upload.wikimedia.org/wikipedia/commons/0/01/charvet_shirt.jpg"),        
        PublicId = "wiki_shirt",
        QualityAnalysis = true,
        Colors = true,        
        Categorization = "google_tagging",
        AutoTagging = 0.8};
var uploadResult = cloudinary.Upload(uploadParams);

|go
resp, err := cld.Upload.Upload(ctx,"https://upload.wikimedia.org/wikipedia/commons/0/01/charvet_shirt.jpg",uploader.UploadParams{
  PublicID:  "wiki_shirt",
        QualityAnalysis: api.Bool(true),
        Colors: api.Bool(true),        
        Categorization: "google_tagging",
        AutoTagging: 0.8
});

|android
MediaManager.get().upload("https://upload.wikimedia.org/wikipedia/commons/0/01/charvet_shirt.jpg")
   .option("public_id", "wiki_shirt")
   .option("quality_analysis", "true")
   .option("colors", "true")
   .option("categorization", "google_tagging")
   .option("auto_tagging", "0.8")
   .dispatch();

|swift
let params = CLDUploadRequestParams()
  .setPublicId("wiki_shirt")
  .setQualityAnalysis(true)
  .setColors(true)
  .setCategorization(google_tagging)
  .setAutoTagging(0.8)
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:"https://upload.wikimedia.org/wikipedia/commons/0/01/charvet_shirt.jpg")!, params: params)

|curl
curl https://api.cloudinary.com/v1_1/demo/image/upload -X POST --data 'file=https://www.example.com/https://upload.wikimedia.org/wikipedia/commons/0/01/charvet_shirt.jpg&public_id="wiki_shirt"&quality_analysis=true&colors=true&categorization="google_tagging"&auto_tagging=true&timestamp=173719931&api_key=436464676&signature=a788d68f86a6f868af'
```

### Programmatic upload with the Node.js SDK video tutorial

Watch this video on how to quickly upload images, videos and other media files to Cloudinary using Cloudinary's Node.js SDK.

  This video is brought to you by Cloudinary's video player - embed your own!Use the controls to set the playback speed, navigate to chapters of interest and select subtitles in your preferred language.

#### Tutorial contents This tutorial presents the following topics. Click a timestamp to jump to that part of the video.
#### Supported programming languages
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=0 :sec=11 :player=cld} | Our tutorial uses [Node.js](node_integration) and server-side scripts to demonstrate the upload capabilities. However, we [support many popular programming languages](cloudinary_sdks), including [Ruby](rails_integration), [PHP](php_integration), [Python](dotnet_integration) and more. 
|

#### Write your script
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=0 :sec=32 :player=cld} | Start writing a script that uses Cloudinary's Upload API to get the image into your Cloudinary product environment. Our example requires two different libraries - the [Cloudinary Node.js SDK](node_integration#installation) and [dotenv](https://www.npmjs.com/package/dotenv), which allows your development environment to [use your Cloudinary credentials](node_integration#configuration) and upload the assets in an authenticated way.
|

#### Retrieve your environment variable
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=0 :sec=50 :player=cld} | Retrieve your environment variable from the [API Keys](product_environment_settings#api_keys) page of the Cloudinary Console Settings, then paste it into a **.env** file in your development project. Do not expose your Cloudinary product environment credentials in your site's frontend and public code.
|

> **NOTE**:
>
> You can no longer access your full credentials directly from the Dashboard. Find your **Cloud name** on the [Dashboard](https://console.cloudinary.com/app/home/dashboard), and all credentials, including **API Key**, **API Secret**, and **API environment variable**, on the [API Keys](https://console.cloudinary.com/app/settings/api-keys) page of the Cloudinary Console Settings.

#### Call the Upload API
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=1 :sec=14 :player=cld} | Call the [Cloudinary Upload API](image_upload_api_reference), then [reference the file you want to upload](node_image_and_video_upload#server_side_upload). 
|

#### Add callback functions
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=1 :sec=19 :player=cld} | Add your [callback functions](https://nodejs.org/en/learn/asynchronous-work/javascript-asynchronous-programming-and-callbacks#callbacks/). This tutorial [uses promises to handle the successes and failures in the code](https://tpiros.dev/blog/promises-in-javascript/).
|

### Ensure script libraries are installed
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=1 :sec=26 :player=cld} | Make sure all of our script's libraries [are properly installed](https://docs.npmjs.com/cli/v7/commands/npm-install) with a simple `npm i` command. If you opening your **package.json** file, you can see all of the packages have been listed as dependencies.
|

#### Run the script and upload the local asset
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=1 :sec=41 :player=cld} | You should have gotten [a successful JSON response](upload_images#upload_response) with lots of data about the uploaded file, including its resolution, file size, format, and more. The file is also now an immediately deliverable asset from a secure, HTTPS URL.
|

#### Upload an asset from a public URL
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=2 :sec=00 :player=cld} | To upload a file from any public URL, [simply enter the full URL of the asset](upload_parameters#upload_from_a_remote_url), instead of the local file path.
|

#### Add parameters to the upload call
{table:class=tutorial-bullets}|  | 
| --- | --- |
|{videotime:id=media :min=2 :sec=19 :player=cld} | You can [edit the file's public ID](upload_parameters#public_id), so the asset is named exactly what you want it to be. It is also possible to [add tags to the asset](image_upload_api_reference#tags_method), so you can easily find and deliver it later. You can even [apply quality analysis features](image_quality_analysis) to provide automation, based on the blurriness or overall size of the asset.

## Basic uploading 

You can upload assets programmatically either by using authenticated uploads that include a signature, or using unauthenticated uploads without a signature but with certain restrictions for security reasons. 

The `upload` API method enables you to upload files with a direct call to Cloudinary by sending an HTTPS POST request to the following Cloudinary REST API URL:

`https://api.cloudinary.com/v1_1/<cloud name>/<resource_type>/upload`

**Where:**

   * `cloud name` is the name of your Cloudinary product environment.
   * `resource_type` is the type of file to upload. Valid values: `image`, `raw`, `video` and `auto` to automatically detect the file type.

For example, to upload an image file to the Cloudinary 'demo' product environment, send an HTTPS POST request to the following URL:

`https://api.cloudinary.com/v1_1/demo/image/upload`

The contents of the POST request you send to Cloudinary depends on whether or not you are making an [authenticated request](#authenticated_requests) or an [unauthenticated request](#unauthenticated_requests).

Uploading is performed synchronously, and once finished, the uploaded asset is immediately available for transformation and delivery. 

> **TIP**:
>
> :title=Tips

> * Use the [auto-upload](migration#lazy_migration_with_auto_upload) feature for lazy migration of all your assets from a remote location to Cloudinary with minimal effort on your side.

> * [Enterprise](https://cloudinary.com/pricing#pricing-enterprise) customers can set up their account to use an [EU or AP data center](image_upload_api_reference#alternative_data_centers_and_endpoints_premium_feature) with the endpoints becoming `api-eu.cloudinary.com` or `api-ap.cloudinary.com` respectively.

### Authenticated requests

Authenticated upload requests are performed over HTTPS using a secure protocol and include an authentication signature that's generated based on your product environment's `cloud_name`, `api_key` and `api_secret` parameters. 

#### Upload with Cloudinary backend SDKs

Cloudinary's [backend SDKs](backend_sdks) wrap the [Upload endpoint](image_upload_api_reference#upload) and automatically generate the authentication signature based on the product environment credentials provided in your SDK configuration. When using an SDK to upload, the only required parameter is the `file` to upload. 

For more details on uploading with SDKs, see the **Upload** page of the relevant [backend SDK](backend_sdks) guide.

**Upload SDK syntax**

The Cloudinary `upload` SDK methods perform authenticated upload API calls over HTTPS using the following syntax:
 
```multi
|ruby 
Cloudinary::Uploader.upload(file, options = {})
  
|php_2
$cloudinary->uploadApi()->upload($file, $options = []);

|python
cloudinary.uploader.upload(file, **options)

|nodejs
cloudinary.v2.uploader.upload(file, options).then(callback);
  
|java
cloudinary.uploader().upload(Object file, Map options);

|csharp
cloudinary.Upload(UploadParams params); 

|go
resp, err := cld.Upload.Upload(ctx, file, uploader.UploadParams{})

|android
MediaManager.get().upload(file).dispatch();

|swift
cloudinary.createUploader().signedUpload(url: file, params: params) 

```

For example, a simple upload of the `sample.jpg` file:

```multi
|ruby 
Cloudinary::Uploader.upload("sample.jpg")
  
|php_2
$cloudinary->uploadApi()->upload("sample.jpg");
  
|python
cloudinary.uploader.upload("sample.jpg")

|nodejs
cloudinary.v2.uploader
.upload("sample.jpg")
.then(result=>console.log(result)); 
  
|java
cloudinary.uploader().upload("sample.jpg", ObjectUtils.emptyMap());

|csharp
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"sample.jpg")};
var uploadResult = cloudinary.Upload(uploadParams);

|go
resp, err := cld.Upload.Upload(ctx, "sample.jpg", uploader.UploadParams{})

|android
MediaManager.get().upload("sample.jpg").dispatch();

|swift
let params = CLDUploadRequestParams()
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: "sample.jpg", params: params) 
```

#### Upload via the REST upload endpoint

You can use Cloudinary's REST API directly for authenticated uploads. The Cloudinary `upload` endpoint performs an authenticated upload API call over HTTPS using the following syntax:

```multi
|curl
https://api.cloudinary.com/v1_1/<cloud name>/<resource_type>/upload -X POST --data '<params>'

```

The Upload API supports multiple authentication methods:

* **[Basic Authentication](#using_basic_authentication)**: Authenticate using your API Key and API Secret via HTTP Basic Auth (no signature calculation required)
* **[Signature-based authentication](#using_signature_based_authentication)**: Manually generate a SHA signature with timestamp

> **INFO**: You should never expose your `api_secret` in client-side code, regardless of which authentication method you use.

##### Using Basic Authentication

Basic Authentication is the simplest way to authenticate Upload API requests from your backend. You provide your API Key and API Secret, and Cloudinary handles the authentication without requiring signature calculation.

**To make an authenticated REST API upload request with Basic Authentication:**

1. **Add your credentials**: Include your API Key and API Secret either in the URL or in an Authorization header.

2. **Add the file parameter**: Specify the file to upload. This can be:
    * The actual data (byte array buffer)
    * The Data URI (Base64 encoded)
    * A remote FTP, HTTP or HTTPS URL of an existing file
    * A private storage bucket (S3 or Google Storage) URL of an allowlisted bucket
    
    For more details, see [File source options](upload_parameters#required_file_parameter).

3. **Optionally, add customization parameters**: Include any of the many optional upload parameters available for [customizing your upload](upload_parameters), such as:
    * Naming parameters
    * Tags and metadata (manually specified or automatically generated)
    * Incoming transformations
    * AI-based analysis options
    
    See the [optional upload parameters](image_upload_api_reference#upload_optional_parameters) reference for the full list. 
    
    > **TIP**: Instead of passing optional parameters directly in the upload call, you can define them in a signed [upload preset](upload_presets) and then pass that preset in your upload call.

**Example with Basic Authentication:**

```curl
curl https://<API_KEY>:<API_SECRET>@api.cloudinary.com/v1_1/<CLOUD_NAME>/image/upload \
  -X POST \
  -F "file=sample.jpg" \
  -F "public_id=my_sample" \
  -F "tags=example,basic_auth"
```

Or using the Authorization header:

```curl
curl https://api.cloudinary.com/v1_1/<CLOUD_NAME>/image/upload \
  -X POST \
  -u "<API_KEY>:<API_SECRET>" \
  -F "file=sample.jpg" \
  -F "public_id=my_sample"
```

##### Using signature-based authentication

You can also authenticate using signature-based authentication, which requires [manually generating the signature](authentication_signatures). See the [Client-side uploading](client_side_uploading) documentation for an example [code explorer to upload multiple files](client_side_uploading#sample_project_upload_multiple_files_using_a_form_signed) from the client-side while using a backend component to generate the signature.

**To make an authenticated REST API upload request with signature-based authentication:**

1. **Add the file parameter**: Specify the file to upload (see options above).

2. **Add the api_key parameter**: Include the unique API Key of your Cloudinary product environment.

3. **Add the timestamp parameter**: Specify Unix time in seconds of the current time (e.g., 1315060076).

4. **Add the signature parameter**: [Generate a signature](authentication_signatures) of all request parameters including the 'timestamp' parameter and any optional parameters added, but excluding the 'api_key', 'resource_type', 'cloud_name' and 'file' parameters, based on your product environment's API secret. The signature is valid for 1 hour. 

5. **Optionally, add customization parameters**: Include any of the optional upload parameters (see above).

**Example with signature-based authentication:**

```curl
curl https://api.cloudinary.com/v1_1/demo/image/upload \
  -X POST \
  --data 'file=sample.jpg&timestamp=173719931&api_key=436464676&signature=a781d61f86a6f818af'
```

### Unauthenticated requests

Unauthenticated upload requests enable you to upload assets without the need to generate an authentication signature on your backend. However, for security reasons, only a small set of upload parameters can be passed directly in an unsigned upload call (see note below). Instead, most unsigned upload options are set via the [unsigned upload preset](upload_presets) that's passed in your unsigned upload call. 

An **upload preset** defines the upload options to apply to all assets that you upload with that preset specified. You can create multiple upload presets for different use cases. For more information on upload presets, see the [upload preset](upload_presets) guide.

#### Perform an unsigned upload with the SDKs

**To perform an unsigned upload with the SDKs:**

1. **Ensure your SDK is configured with your cloud name**. For details, see the relevant [backend SDK](backend_sdks) guide.
2. **Call the unsigned_upload method**: Use your SDK's `unsigned_upload` method with your file.
3. **Set the upload_preset parameter**: Specify the name of your unsigned upload preset.

For example, to upload the `sample.jpg` file with the `unsigned_1` upload preset using an SDK:

```multi
|ruby
Cloudinary::Uploader.unsigned_upload("sample.jpg", "unsigned_1")

|php_2
$cloudinary->uploadApi()->unsignedUpload("sample.jpg", "unsigned_1");

|python
cloudinary.uploader.unsigned_upload("sample.jpg", "unsigned_1")

|nodejs
cloudinary.v2.uploader
.unsigned_upload("sample.jpg", "unsigned_1")
.then(result=>console.log(result)); 
                           
|java
cloudinary.uploader().unsignedUpload("sample.jpg", "unsigned_1");

|csharp
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"sample.jpg"),
  Unsigned = true,
  UploadPreset = "unsigned_1"};
var uploadResult = cloudinary.Upload(uploadParams);

|android
MediaManager.get().upload("sample.jpg")
  .unsigned("unsigned_1").dispatch();

|go
resp, err := cld.Upload.UnsignedUpload(ctx, "sample.jpg", "unsigned_1", uploader.UploadParams{
	Unsigned: api.Bool(true)})

|swift
let request = cloudinary.createUploader().upload(
  url: "sample.jpg", uploadPreset: "unsigned_1")

|cli
cld uploader unsigned_upload "sample.jpg" "unsigned_1"
```

#### Perform an unauthenticated REST API upload request

To make an unauthenticated upload request, include the following required parameters:

1. **Add the file parameter**: Specify the file to upload. This can be:
    * The actual data (byte array buffer)
    * The Data URI (Base64 encoded)
    * A remote FTP, HTTP or HTTPS URL of an existing file
    * A private storage bucket (S3 or Google Storage) URL of an allowlisted bucket
    
    For more details, see [File source options](upload_parameters#required_file_parameter).

2. **Add the upload_preset parameter**: Specify the name of an unsigned [upload preset](upload_presets) that you defined for unsigned uploading.

For example: 

```multi
|curl
curl https://api.cloudinary.com/v1_1/demo/image/upload -X POST --data 'file=sample.jpg&upload_preset=unsigned_1'  
```

[Try out unsigned uploads in a code explorer example](client_side_uploading#code_explorer_upload_multiple_files_using_a_form_unsigned)

> **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 asset upload

To support the upload of large files, the Cloudinary SDKs include a method which offers a degree of tolerance for network issues. The `upload_large` method uploads a large file to the cloud in chunks, and is required for any files that are larger than 100 MB. This is often relevant for video files, as they tend to have larger files sizes.

#### Upload a large file in chunks

**To upload a large file using the SDK 'upload_large' method:**

1. **Call the upload_large method**: Use your SDK's `upload_large` method (or equivalent) with your file.

2. **Specify the resource_type parameter**: By default, backend SDKs set the `resource_type` to `image`. Specify the `resource_type` parameter to match your file type. For example, set `resource_type` to `video` for video files or `auto` if you don't know in advance what type to expect. For more details about the `resource_type` option, see [Asset types](upload_parameters#asset_types).

3. **For files larger than 20 GB, set async to true**: Add the `async` parameter set to `true` to upload the file asynchronously.

4. **Optionally, customize the chunk_size**: The default chunk size is 20 MB, but you can set it as low as 5 MB using the `chunk_size` parameter.

> **TIP**: If you can't or don't want to use the SDKs, you can make use of the byte Content-Range entity-header HTTP specification to send the file in multiple calls with the ['upload' endpoint of the REST API](#basic_uploading). See the [Client-side uploading](client_side_uploading) documentation for an example [code explorer to upload large files in chunks](client_side_uploading#code_explorer_chunked_asset_upload_from_the_client_side) from the client-side.

> **NOTE**: If you need to upload files larger than 100 GB, you can [contact support](https://support.cloudinary.com/hc/en-us/requests/new) to increase your upload limit. You can see your current usage limits in your [Console Account Settings](https://console.cloudinary.com/app/settings/account).

For example, uploading a large video file named `my_large_video.mp4`:

```multi
|ruby 
Cloudinary::Uploader.upload_large("my_large_video.mp4", 
    resource_type: "video")

|php_2
// No uploadLarge method. The upload method automatically applies chunked uploading for large files.
$cloudinary->uploadApi()->upload("my_large_video.mp4",
  ["resource_type" => "video"]);     

|python
cloudinary.uploader.upload_large("my_large_video.mp4", 
  resource_type = "video")

|nodejs
cloudinary.v2.uploader
  .upload_large("my_large_video.mp4", { resource_type: "video" })
  .then(result => console.log(result))
  .catch(error => console.error(error));

|java
cloudinary.uploader().uploadLarge("my_large_video.mp4",
  ObjectUtils.asMap("resource_type", "video"));

|csharp
var uploadParams = new VideoUploadParams(){ // This class sets the resource type to Video
  File = new FileDescription(@"my_large_video.mp4")};
var uploadResult = cloudinary.UploadLarge(uploadParams);

|go
// Large files are automatically chunked using the default chunk size.
resp, err := cld.Upload.Upload(ctx, "my_large_video.mp4", uploader.UploadParams{
		ResourceType: "video"}) 

|android
MediaManager.get().upload("my_large_video.mp4")
  .option("resource_type", "video").dispatch();

|swift
let params = CLDUploadRequestParams()
  .setResourseType("video")
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().signedUploadLarge(
  url: "my_large_video.mp4", params: params)

|cli
cld uploader upload_large "my_large_video.mp4" resource_type="video"
```
  
By default, the chunk size is set to 20 MB but can be set to as low as 5 MB by using the `chunk_size` parameter. For example, uploading a large video file named `my_large_video.mp4` and setting chunk size to 6 MB:

```multi
|ruby  
Cloudinary::Uploader.upload_large("my_large_video.mp4",
  resource_type: "video", 
  chunk_size: 6_000_000)

|php_2
// No distinct uploadLarge method. The upload method automatically applies chunked uploading for large files.
$cloudinary->uploadApi()->upload("my_large_video.mp4", [
    "resource_type" => "video", 
    "chunk_size" => 6000000]);

|python
cloudinary.uploader.upload_large("my_large_video.mp4", 
  resource_type = "video", 
  chunk_size = 6000000)

|nodejs
cloudinary.v2.uploader
  .upload_large("my_large_video.mp4", { resource_type: "video", chunk_size: 6000000 })
  .then(result => console.log(result))
  .catch(error => console.error(error));

|java
cloudinary.uploader().uploadLarge("my_large_video.mp4",
  ObjectUtils.asMap(
    "resource_type", "video", 
    "chunk_size", 6000000));

|csharp
var uploadParams = new ImageUploadParams(){ // This class sets the resource type to Video
  File = new FileDescription(@"my_large_video.mp4")};
var uploadResult = cloudinary.UploadLarge(uploadParams, 6000000);

|go
var largeUploader, _ = uploader.New() 
largeUploader.Config.API.ChunkSize = 6000000

resp, err := cld.Upload.Upload(ctx, "my_large_video.mp4", uploader.UploadParams{
		ResourceType: "video"}) 

|android
MediaManager.get().getCloudinary().uploader().uploadLarge("my_large_video.mp4", options, 6000000);

|swift
let params = CLDUploadRequestParams()
  .setResourceType("video")
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().signedUploadLarge(
  url: "my_large_video.mp4", params: params, chunkSize: 6000000)

|cli
cld uploader upload_large "my_large_video.mp4" resource_type="video" chunk_size=6000000
```

> **NOTE**: There are multiple responses to a chunked upload: one after each chunk that only includes basic information plus the `done : false` parameter, and a full upload response that's returned after the final chunk is uploaded with `done: true` included in the response.

> **TIP**:
>
> The [Node.js SDK](node_image_and_video_upload#node_js_upload_methods) has several different methods for uploading files, including some that take advantage of Node.js's **stream** functionality.

## Upload response

A successful upload API call returns a response that includes the HTTP and HTTPS URLs for accessing the uploaded file, as well as additional information regarding the uploaded asset. Among these are the assigned public ID and current version of the asset (used in the [Media Library](https://console.cloudinary.com/console/media_library/search), Admin API, and for building transformation and delivery URLs), the asset's dimensions, the file format and a signature for verifying the response. Depending on the optional parameters passed, the response might also include valuable analysis data such as detected faces, prominent colors, exif and other embedded metadata, quality/accessibility and other sophisticated media analysis data.

The exact keys returned in the response may vary depending on the parameters passed in your upload call. For details on these parameters and the response fields they influence, see the [Upload API parameters table](image_upload_api_reference#upload_optional_parameters).
> **INFO**: Cloudinary may add more fields to API responses and notifications in the future, so please ensure that your response parsing remains forward compatible and won't break as a result of unknown fields.

The following is an example of the JSON response returned:

```json
{
  "asset_id": "3515c6000a548515f1134043f9785c2f",
  "public_id": "gotjephlnz2jgiu20zni",
  "version": 1719307544,
  "version_id": "7d2cc533bee9ff39f7da7414b61fce7e",
  "signature": "d0b1009e3271a942836c25756ce3e04d205bf754",
  "width": 1920,
  "height": 1441,
  "format": "jpg",
  "resource_type": "image",
  "created_at": "2024-06-25T09:25:44Z",
  "tags": [],
  "pages": 1,
  "bytes": 896838,
  "type": "upload",
  "etag": "2a2df1d2d2c3b675521e866599273083",
  "placeholder": false,
  "url": "http://res.cloudinary.com/cld-docs/image/upload/v1719307544/gotjephlnz2jgiu20zni.jpg",
  "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/v1719307544/gotjephlnz2jgiu20zni.jpg",
  "asset_folder": "",
  "display_name": "gotjephlnz2jgiu20zni",
  "original_filename": "sample",
  "api_key": "614335564976464"
}
```

> **NOTE**: Although the URLs returned in the response are given with the [version number](image_transformations#asset_versions), including the version in the delivery URL is optional.

### Error handling

Once the POST request is received and processed by Cloudinary, the Upload API returns the status of requests using one of the following HTTP status codes:

* 200 - OK. Successful.
* 400 - Bad request. Invalid request parameters.
* 401 - Authorization required.
* 403 - Not allowed.
* 404 - Not found.
* 420 - Rate limited.
* 500 - Internal error. Contact support. 

In the case of wrong usage of the API or an error, Cloudinary's response is returned with a non-OK (not 200) HTTP Status code and a body with the following JSON format:

```javascript
{ error: { message: "<< Error explanation here >>" } }
```

## Upload considerations

There are various ways to upload your resources to your Cloudinary account. Cloudinary supports making both [authenticated requests](#authenticated_requests) that require a signature generated on your backend, and [unauthenticated requests](#unauthenticated_requests) with a restricted set of supported parameters. 

The following table summarizes the main options to upload assets and some considerations to take into account for each of them:

{table:class=no-borders overview wide-lastcol-40} Option | Description | Considerations
---|---|---
[Cloudinary backend SDKs](#authenticated_requests)  | The Cloudinary backend SDKs wrap the upload API, including taking care of the upload itself, the signature authentication and the response verification. |  ✅ Significantly simplifies the upload code compared to directly calling the REST API ✅ Automatically generates an authentication signature and validates the response   ✅ Enables you to code in your chosen language   ✅  Provides built-in support for uploading large files with chunked uploading
[Upload widget](upload_widget)  | An interactive, feature-rich interface you can embed in your website or application to allow your users to upload assets directly to Cloudinary. | ✅  No need to develop an in-house interactive file upload solution  ✅  Simple to integrate ✅  Can be used for unauthenticated client-side uploads  ✅  Enables uploading directly from a variety of social media & stock photo accounts
['upload' endpoint of the REST API](#basic_uploading)  | The `upload` endpoint of the Cloudinary API supports making both [authenticated requests](#authenticated_requests) that require a signature be generated on your backend, and [unauthenticated requests](#unauthenticated_requests) with a restricted set of supported parameters. |  ✅  Can be used for unauthenticated client-side requests  ✅ Useful when coding in a language not covered by Cloudinary's SDKs💡 Requires manually coding the upload and validating the response💡 Requires a function on your backend to generate the signature for authenticated calls
[Direct upload from a browser](client_side_uploading#direct_uploading_from_the_browser_via_a_backend_sdk)  | The Cloudinary Backend SDKs can also be used to automatically add a file input field to your form that uploads files directly to Cloudinary,  bypassing your own servers.  |   ✅  Uploads directly to your account, bypassing your own servers 💡 Requires additional setup and configuration 💡 Requires the Cloudinary jQuery plugin 
[The Cloudinary CLI](cloudinary_cli)   | The Cloudinary CLI (Command Line Interface) enables you to interact with Cloudinary through the command line and provides additional features and helper commands. |   ✅ Simple to use ✅  Useful for quickly uploading assets without setting up a formal coding environment ✅  Useful for experimenting with upload parameters and behavior ✅ Upload-specific helper functions (e.g., sync) not directly provided via the other upload options
[Lazy migration](migration#lazy_migration_with_auto_upload) | Cloudinary's lazy migration with the auto-upload feature enables you to migrate files on demand from a remote location, where each asset is automatically uploaded to Cloudinary the first time the delivery URL for that asset is requested. |  ✅  Simple to implement  ✅ Only upload the assets you really need 💡 Not suitable if there's a deadline when the remote content will be unavailable
[Media Library](https://console.cloudinary.com/console/media_library/search)  | The Media Library in the Cloudinary Console lets you upload assets to your account using drag and drop or the built-in Upload Widget. |  ✅ Simple to use  ✅  Useful for quickly uploading assets without dealing with code ✅  Useful for experimenting with upload preset behavior 💡 Less suitable as a primary means of uploading assets compared to programmatic solutions
[Integrations](integrations)  | Cloudinary has developed built-in integrations with many leading eCommerce, CMS and PIM platforms. |  ✅  Enables platform users to upload to Cloudinary from directly within the platform UI 💡 Requires initial set up and configuration by a platform administrator 💡 Less suitable as a primary means of uploading assets compared to programmatic solutions
[Media Library widget](media_library_widget)  | The Media Library widget enables embedding all the Cloudinary Media Library UI capabilities, including upload, into another application's UI. | ✅ Useful for implementing your own Cloudinary integration 💡 Less suitable as a primary means of uploading assets at scale compared to programmatic solutions

> **TIP**:
>
> :title=Tips:

> * [MediaFlows](https://console.cloudinary.com/mediaflows), Cloudinary’s drag-and-drop workflow builder for image and video, offers the option to automate image upload with a low-code implementation. See MediaFlow’s documentation on media upload [here](mediaflows_block_reference#upload_media). 

> * Usage limits for uploading, transforming and delivering files depend on your Cloudinary [plan](https://cloudinary.com/pricing). For details, check the **Account** tab in your Cloudinary Console **Settings**.

## Clara Denari mini-mystery game

  
    
    
      
      
        🔍 The Case of the Sapphire Earrings
        A Clara Denari Mini Mystery
      
    
    
    
    
      
        
        
          
            
            
              Hey! I need your help. 🤔 I found sapphire earrings in my backyard, but my neighbor Mrs. Patterson claims they're hers: a family heirloom from her grandmother.
              She has an old photo to prove it, but it's so blurry I can't tell if the earrings match. Can you help me upload it to Cloudinary with AI restoration?
              Let's see if Mrs. Patterson's story checks out!
            
          
        
        
        
        
          🔍 Evidence
          
            
              
                
              
              The earrings I found
            
            
              
                
              
              Mrs. Patterson's blurry photo
            
          
        
        
        
        
          
            🎮 Upload the Photo
          
        
      
    

    
        
          
            
            
              
              
                
                
                  
                  
                  
                
              
              
              
              
                
                
                  Perfect! Let's use the upload function to both upload and restore the photo using Cloudinary's AI. ✨
                  First, choose which SDK you want to use:
                  
                    Node.js
                    Python
                    Ruby
                    PHP
                    Java
                    Go
                  
                
              
              
              
              
                
                  
                  
                  
                
              
              
              
              
                
                
                  Cool, you chose Node.js! Use these parameters and values to edit the starter code in the editor below:
                  
                    • Upload file:
                    <code id="clara-mystery__file-param">file_name → <code>grandma_photo_1960.png
                    
                    • Restore photo:
                    param1: <code id="clara-mystery__param1-name">transformation
                    value1: <code id="clara-mystery__value1-name">e_gen_restore
                    
                    • Name uploaded photo:
                    param2: <code id="clara-mystery__param2-name">public_id
                    value2: <code>earrings_restored
                    
                    • Store in folder:
                    param3: <code id="clara-mystery__param3-name">asset_folder
                    value3: <code>evidence
                  
                
              
              
              
              
            
            
            
            
              📸 Photo to Restore
              
                
                  
                    
                  
                  grandma_photo_1960.png
                
              
            
            
            
            
              

  
    
      Node.js
      Python
      Ruby
      PHP
      Java
      Go
    
    💡 Need a hint?
  
  
  
    cloudinary.v2.uploader.upload('file_name', {
  param1: 'value1',
  param2: 'value2',
  param3: 'value3'
})
  
  
  
    cloudinary.uploader.upload('file_name',
  param1='value1',
  param2='value2',
  param3='value3')
  
  
  
    Cloudinary::Uploader.upload('file_name',
  param1: 'value1',
  param2: 'value2',
  param3: 'value3')
  
  
  
    (new UploadApi())->upload('file_name', [
  'param1' => 'value1',
  'param2' => 'value2',
  'param3' => 'value3'
]);
  
  
  
    cloudinary.uploader().upload("file_name",
  ObjectUtils.asMap(
    "param1", "value1",
    "param2", "value2",
    "param3", "value3"
  ));
  
  
  
    cld.Upload.Upload(ctx, "FileName", uploader.UploadParams{
  Param1: "value1",
  Param2: "value2",
  Param3: "value3"
})
  

              
              
              
                ✨ Upload & Restore!
                Reset Code
              
            
          
        
        
        
        
        
          
            
            
              
              
                
                
                  
                  
                  
                
              
              
              
              
                
                
                  Amazing work! 🎉 The upload was successful!
                  You applied the AI restore transformation first, and then uploaded the transformed, restored version to Cloudinary.
                  
                
              
              
              
              
                
                
                  
                  
                  
                
              
              
              
              
                
                
                  Now I need you to find the secure_url in the response. That's the URL you can use to access the restored image.
                  Copy that URL and paste it below. Let's see if the AI restoration worked! 🔍
                  
                
              
              
              
              
            
            
            
            
              📋 Upload Response
              
                <pre class="clara-mystery__code" style="margin: 0;"><code>{
  "asset_id": "1c3547643785ba27005340620d46d6ba",
  "public_id": "earrings_restored",
  "version": 1763564796,
  "width": 1200,
  "height": 1200,
  "format": "jpg",
  "resource_type": "image",
  "created_at": "2025-11-19T15:06:36Z",
  "bytes": 271366,
  "url": "http://res.cloudinary.com/.../earrings_restored.png",
  "secure_url": "https://res.cloudinary.com/demo/image/upload/v1768438613/earrings_restored.png",
  "original_filename": "grandma_photo_1960"
}
              
            
            
            
            
              
                Paste the secure URL here:
              
              
                
                
                
                
                🔓 Show Me the Restored Photo!
              
            
          
        
        
        
        
        
          
            
            
              
              
                
                
                  
                  
                  
                
              
              
              
              
                
                
                  Perfect! 🎉 Now drag the slider to see the incredible AI restoration in action!
                
              
              
              
              <div class="clara-mystery__chat-bubble" id="clara-mystery__typing-step3-2" hidden style="display: none;">
                
                
                  
                  
                  
                
              
              
              
              
                
                
                  The earrings in the photo do look similar to the ones I found...
                  Do you think the earrings in Mrs. Patterson's restored photo match the earrings I found?
                
              
              
              
              
                Yes
                No
              
              
              
              
                
                
                  
                  
                  
                
              
              
              
              
                
                
                  
                
              
              
              
              
                
                
                  
                  
                  
                
              
              
              
              
                
                
                  💡 Key Takeaways: You've learned how to:
                  ✓ Enhance blurry, low-quality images with <code>e_gen_restore
                  ✓ Customize your upload by adding transformations and other parameters.
                  
                  🚀 Next Steps: Try it in your environment!
                  Click Back for the game example, or explore more upload customization options:
                  
                  
                    📤 Customize Your Uploads
                  
                
              
              
              
              
                
                
                  
                  
                  
                
              
              
              
              
                
                
                  When you're done with your code, help me settle this mystery! Let's run a color analysis in my lab to see if these earrings really match. 🔬
                
              
              
              
              
              
            
            
            
            
              ✨ Restoration Complete!
              
                Drag the slider to see the before and after!
              
              
              
              
              
                
                
              
              
              
              
                ← After (AI Restored!)
                Before (Blurry) →
              
              
              
                
                  
                
                The earrings I found
                
                  Note: This mini‑mystery uses a simulated upload. In real apps, authenticate uploads with your Cloudinary API key and secret on a secure server, and never expose those credentials in client‑side code.
                
              
            
            
          
        
        
        
        
        
          ← Back
          Next →
          🔄 Play Again
        
        
      
    
  

  
    📖 Cloudinary Upload Reference
    ✕
  
  
    
    
  

  
    
      💡 Hint
      ✕
    
    
      Remember the upload structure:
      
        // Each SDK has an uploader with an upload method:
        uploader.upload(filename, {parameters})
      
      
      Quick tips:
      
        The filename comes first, then the parameters object
        Use the exact filename: <code>grandma_photo_1960.png
        Watch your syntax! Each language has slightly different formats:
          
            Node.js/Python: <code>param: 'value' or <code>param='value'
            Ruby: <code>param: 'value'
            PHP: <code>'param' => 'value'
            Java: <code>"param", "value" (comma-separated pairs)
            Go: <code>Param: "value" (PascalCase)
          
        
        Don't forget commas between parameters!
      
      
      
        Still stuck? Look at the placeholder code in your selected language tab - it shows the basic structure you need.
      
    
  

> **See also**:
>
> * [Upload API Reference](image_upload_api_reference): Provides both REST and SDK syntax, parameter details, and examples for all methods of the Upload API.

> * [Upload Add-ons](cloudinary_add_ons): Many of Cloudinary's add-ons can be activated by adding a parameter in your upload call. These add-ons enable you to take advantage of special deep-learning, AI, and other analytical capabilities offered by Cloudinary as well as other vision and image processing partners. 

> * [Asset management](asset_management): Covers options for managing your uploaded assets programmatically, including various CRUD options, backups and version management, notifications and webhooks, and authentication and signature options.* [User-generated content guide](user_generated_content): Upload is a key component of allowing user-generated content to be displayed on your site. Learn about all the features you can take advantage of when handling user-generated content.

