Skip to navigation

JS API clients

JS API clients handle uploads and file operations by wrapping Uploadcare Upload API and REST API. You can use it from within your Node.js app and in a browser.

JS API clients GitHub →

Features

Uploading (Upload API):

  • Upload files from local storage and URLs (up to 5 TB)
  • Multipart uploading for large files
  • Track uploading progress
  • Bulk file uploading
  • Uploading network to speed uploading jobs (like CDN)
  • Signed uploads

File management (REST API):

  • Get file info and perform various operations (store/delete/copy) with them
  • Manage metadata
  • Manage webhooks
  • Convert documents
  • Encode and transform videos
  • Secure authentication

Image processing (URL API):

  • Compression
  • Geometry
  • Colors
  • Definition
  • Image and text overlays
  • Rotations
  • Recognition
  • File info
  • Proxy (fetch)

Requirements

Node.js 16 or later.

Install

npm install @uploadcare/upload-client
npm install @uploadcare/rest-client
npm install @uploadcare/signed-uploads

Usage examples

To access the Upload Client High-Level API, you need to create an instance of UploadClient providing the necessary settings. Specifying YOUR_PUBLIC_KEY is mandatory. It points to the specific Uploadcare project:

import { UploadClient } from '@uploadcare/upload-client'
const client = new UploadClient({ publicKey: 'YOUR_PUBLIC_KEY' })

Once the UploadClient instance is created, you can start using the wrapper to upload files from binary data:

client
.uploadFile(fileData)
.then(file => console.log(file.uuid))

Note: The store option accepts true, false, or "auto". String values like "true" or "false" are not accepted.

Signed uploads

For signed uploads, use the @uploadcare/signed-uploads package. It mints the auth tokens that new projects should use. Both packages need 6.23.0 or later. Upload Client versions that predate authToken ignore it without a warning and the request goes out unsigned.

import { generateAuthToken } from '@uploadcare/signed-uploads'
// On your server. The token can also carry an endpoint scope and an
// operation limit.
const authToken = generateAuthToken('YOUR_SECRET_KEY', {
lifetime: 30 * 60 * 1000 // 30 minutes
})
const client = new UploadClient({
publicKey: 'YOUR_PUBLIC_KEY',
authToken,
})

In the browser, pass a function instead of a token and wrap your fetch in AuthTokenCache. It refreshes the token before it expires and shares one fetch across uploads that start together:

import { AuthTokenCache } from '@uploadcare/signed-uploads/client'
import { uploadFile } from '@uploadcare/upload-client'
const tokens = new AuthTokenCache({
fetchToken: async () => {
const response = await fetch('/uploadcare-token')
// `fetch` does not throw on a 500, and a body without a token gives
// `undefined`. Check both, so a failure says what actually went wrong.
if (!response.ok) throw new Error(`token endpoint: ${response.status}`)
const { token } = await response.json()
if (!token) throw new Error('token endpoint returned no token')
return token
}
})
// Pass the cache itself: it is already the `{ getToken, invalidate }` shape
// the client wants, so the client can drop a refused token on its own.
await uploadFile(file, { publicKey: 'YOUR_PUBLIC_KEY', authToken: tokens })

The /client entry point is browser-safe: it holds no signing code and never touches your secret key. Call tokens.invalidate() when the signed-in user changes. A short-lived token handles the rest on its own, and the cache holds nothing across a reload: it lives in the instance, with no localStorage or cookie behind it, so a fresh page always calls fetchToken again. A cache built per request on a server is the same story, which is why one shared at module scope would hand a visitor the previous visitor’s token. The AuthTokenCache reference covers its remaining options, including initialToken for a token rendered into the page during SSR, and what to watch for when the cache runs on a server.

If your function throws, the upload rejects with an AuthTokenResolverError carrying the original failure on cause. Nothing was sent, so nothing is retried:

import { AuthTokenResolverError, uploadFile } from '@uploadcare/upload-client'
async function upload(file) {
try {
return await uploadFile(file, { publicKey: 'YOUR_PUBLIC_KEY', authToken: tokens })
} catch (error) {
if (error instanceof AuthTokenResolverError) {
// Your token endpoint failed; nothing was sent to Uploadcare.
console.warn('could not get an upload token', error.cause)
}
throw error
}
}

To tell a lost session from a dead endpoint, include your endpoint’s HTTP status in what the function throws, then check it on error.cause: a 401 means the user has to sign in again, while a 500 or a network error is worth retrying.

When Uploadcare refuses the token as expired (AccessTokenExpiredError) or out of operations (OperationsLimitExceededError), the client calls tokens.invalidate() for you, fetches a new token and retries the request once. Reaching your handler with either code means the second token was refused too, so invalidating again changes nothing: see troubleshooting. This only happens when authToken is a function or a cache; a plain token string is sent as is and never retried. ScopeForbiddenError is never retried either, since a reissued token carries the same scope.

The same package also generates the signature and expire pair:

import { generateSecureSignature } from '@uploadcare/signed-uploads'
// Option A: expiration as timestamp in milliseconds
const { secureSignature, secureExpire } = generateSecureSignature('YOUR_SECRET_KEY', {
expire: Date.now() + 60 * 30 * 1000 // 30 minutes from now
})
// Option B: expiration as a Date object
const { secureSignature, secureExpire } = generateSecureSignature('YOUR_SECRET_KEY', {
expire: new Date("2099-01-01")
})
const client = new UploadClient({
publicKey: 'YOUR_PUBLIC_KEY',
secureSignature,
secureExpire,
})

Bulk uploads

Use Queue to control concurrency when uploading multiple files:

import { Queue, uploadFile } from '@uploadcare/upload-client'
const queue = new Queue(10) // max 10 concurrent uploads
await queue.add(() => uploadFile(file1, { publicKey: 'YOUR_PUBLIC_KEY' }))
await queue.add(() => uploadFile(file2, { publicKey: 'YOUR_PUBLIC_KEY' }))

Error handling

import { UploadError, NetworkError } from '@uploadcare/upload-client'
try {
const file = await client.uploadFile(fileData)
} catch (error) {
if (error instanceof NetworkError) {
console.error('Network error:', error.message)
} else if (error instanceof UploadError) {
console.error('Upload error:', error.message)
}
}

Authentication

For server-side usage, use UploadcareSimpleAuthSchema:

import { UploadcareSimpleAuthSchema } from '@uploadcare/rest-client'
const authSchema = new UploadcareSimpleAuthSchema({
publicKey: 'YOUR_PUBLIC_KEY',
secretKey: 'YOUR_SECRET_KEY',
})

Warning: Never use UploadcareSimpleAuthSchema on the client side: it exposes your secret key. For client-side usage, use UploadcareAuthSchema with a signatureResolver that delegates signing to your backend.

For client-side usage:

import { UploadcareAuthSchema } from '@uploadcare/rest-client'
const authSchema = new UploadcareAuthSchema({
publicKey: 'YOUR_PUBLIC_KEY',
signatureResolver: async (signString) => {
const response = await fetch(`/sign-request?signString=${encodeURIComponent(signString)}`)
return response.text()
}
})

Pagination

Use the paginate helper to iterate through all pages of results:

import { listOfFiles, paginate } from '@uploadcare/rest-client'
const pages = paginate(listOfFiles)({}, { authSchema })
for await (const page of pages) {
console.log(page)
}

File conversion

Convert video and document files using the unified convert API:

import { convert, conversionJobStatus, ConversionType } from '@uploadcare/rest-client'
// Video conversion
await convert(
{ type: ConversionType.VIDEO, paths: [':uuid/video/-/size/x720/'], store: false },
{ authSchema }
)
// Document conversion
await convert(
{ type: ConversionType.DOCUMENT, paths: [':uuid/document/-/format/pdf/'], store: false },
{ authSchema }
)
// Check conversion job status
await conversionJobStatus(
{ type: ConversionType.VIDEO, token: 12345 },
{ authSchema }
)

Search files

import { searchFiles } from '@uploadcare/rest-client'
const response = await searchFiles({ query: 'invoice' }, { authSchema })
response.results.forEach((file) => console.log(file.uuid, file.originalFilename))

File tags

import { getTags, updateTags } from '@uploadcare/rest-client'
const { tags } = await getTags({ uuid: 'YOUR_FILE_UUID' }, { authSchema })
await updateTags({ uuid: 'YOUR_FILE_UUID', add: ['featured'], delete: ['draft'] }, { authSchema })

Full documentation

Read the full documentation on JS API clients GitHub.