# Uppy — full documentation > The open source JavaScript file uploader --- Source: https://uppy.io/docs/quick-start # Quick start Uppy is a sleek, modular JavaScript file uploader that integrates seamlessly with any application. It’s fast, has a comprehensible API and lets you worry about more important problems than building a file uploader. :::tip You can take Uppy for a walk inside StackBlitz with a [minimal drag & drop](https://stackblitz.com/edit/vitejs-vite-yzbujq?file=main.js/g) experience or a [full featured dashboard](https://stackblitz.com/edit/vitejs-vite-zaqyaf?file=main.js). ::: - [I want a full featured, extendable UI](/docs/dashboard) — Learn more about the Dashboard - [I want a minimal drag & drop UI](/docs/drag-drop) — We have a lightweight plugin for that - [Which uploader do I need?](/docs/guides/choosing-uploader) — Choosing the uploader you need - [I want to add files from remote sources](/docs/companion) — Such as Google Drive, Dropbox, OneDrive - [I’d like a project example](https://github.com/transloadit/uppy/tree/main/examples) — Try out one of our extensive example projects - [I have a question](https://community.transloadit.com/) — Our community forum is there to help ## Framework integrations *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/quick-start for the full page.)* --- Source: https://uppy.io/docs/ai-image # AI image generator The `@uppy/image-generator` plugin lets users generate images from text prompts using [Transloadit’s 🤖 `/image/generate` Robot](https://transloadit.com/docs/robots/image-generate/). Under the hood it asks your backend for signed Transloadit parameters, sends those to Transloadit, and then lets users pick the generated images as if they were regular files. You can learn more about the underlying AI service and common use cases in Transloadit’s blog post [“Generate stunning images from text using AI”](https://transloadit.com/blog/2025/04/ai-image-generation/). ::::tip The plugin focuses on wiring Uppy into Transloadit’s AI image generation. It does **not** manage your Transloadit Templates for you — instead, you send `steps` at runtime from your server, similar to the “overruling templates at runtime” flow described [in the Transloadit docs](https://transloadit.com/docs/topics/templates/#overruling-templates-at-runtime). :::: ## When should I use this? Use `@uppy/image-generator` when you want users to generate images on the fly instead of uploading existing files. Typical examples: - Product mockups or marketing visuals where users describe the scene instead of uploading photos. - Illustrations for documents, blog posts, or educational content. - Quick concept art, avatars, or backgrounds that are generated as part of your app’s flow. ## Install **NPM** ```shell npm install @uppy/image-generator ``` **Yarn** ```shell yarn add @uppy/image-generator ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use The integration has **two parts**: 1. **Client-side Uppy configuration**, where you register the plugin and provide an `assemblyOptions` callback. 2. **A server-side endpoint** that returns a signed `{ params, signature }` pair for Transloadit. ### 1. Client-side Uppy setup ```js {3,7,11,17} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import ImageGenerator from '@uppy/image-generator'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; import '@uppy/image-generator/css/style.min.css'; const uppy = new Uppy(); uppy.use(Dashboard, { inline: true, target: 'body' }).use(ImageGenerator, { // Called every time the user submits a new prompt assemblyOptions: async (prompt) => { const res = await fetch( `/assembly-options?prompt=${encodeURIComponent(prompt)}`, ); if (!res.ok) { throw new Error('Failed to load Transloadit options'); } // Should resolve to: { params, signature } return res.json(); }, }); ``` When the user enters a prompt in the Image Generator view, Uppy: 1. Calls your `assemblyOptions(prompt)` function. 2. Expects it to resolve with a `{ params, signature }` object. 3. Uses those values to start a Transloadit Assembly that runs the 🤖 `/image/generate` Robot. 4. Displays the generated images so users can pick which ones to add to their upload. ::::note Because we send `steps` directly from the browser, **you must use signature authentication** on your server to keep your Transloadit secret key safe. The `assemblyOptions` callback only ever sees the final `{ params, signature }` pair. For language-specific examples (PHP, Ruby, Go, etc.), see [Transloadit’s authentication docs](https://transloadit.com/docs/api/authentication/). :::: ### 2. Server-side: signing Transloadit parameters (Node.js) Below is a Node.js example that: - Signs Transloadit `params` using your `TRANSLOADIT_KEY` and `TRANSLOADIT_SECRET`. - Sends a single 🤖 `/image/generate` step. - Returns `{ params, signature }` to the browser. ```js showLineNumbers import crypto from 'node:crypto'; function utcDateString(ms) { return new Date(ms) .toISOString() .replace(/-/g, '/') .replace(/T/, ' ') .replace(/\.\d+Z$/, '+00:00'); } export function createAiImageAssemblyOptions(prompt) { // Expire 1 hour from now (value in milliseconds) const expires = utcDateString(Date.now() + 1 * 60 * 60 * 1000); const authKey = process.env.TRANSLOADIT_KEY; const authSecret = process.env.TRANSLOADIT_SECRET; const params = JSON.stringify({ auth: { key: authKey, expires, }, // Must not contain any more steps; the only step here should be /image/generate steps: { generated_image: { // You can name this step however you like robot: '/image/generate', result: true, // required so the generated files are returned // These are up to you; see the /image/generate docs for all options aspect_ratio: '2:3', model: 'flux-1.1-pro-ultra', // The text prompt coming from the browser (required) prompt, // How many variants to generate num_outputs: 2, }, }, }); const signatureBytes = crypto .createHmac('sha384', authSecret) .update(Buffer.from(params, 'utf-8')); // Prefix the hash with the algorithm so Transloadit knows how to verify it const signature = `sha384:${signatureBytes.digest('hex')}`; return { params, signature }; } ``` You can now expose this logic via a small HTTP endpoint: For a complete overview of all parameters (such as `format`, `height`, `width`, `seed`, `style`, and `aspect_ratio`) and supported models, see the [`/image/generate` Robot documentation](https://transloadit.com/docs/robots/image-generate/). The blog post [`Generate stunning images from text using AI`](https://transloadit.com/blog/2025/04/ai-image-generation/) also has more guidance on crafting prompts and choosing models. ## API ### Options #### `id` A unique identifier for this plugin (`string`, default: `'ImageGenerator'`). #### `target` DOM element, CSS selector, or plugin to place the Image Generator view into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `assemblyOptions` Callback that returns Transloadit parameters and signature for a given prompt (`(prompt: string) => Promise<{ params, signature }>`; **required**). ```js uppy.use(ImageGenerator, { assemblyOptions: async (prompt) => { const res = await fetch( `/assembly-options?prompt=${encodeURIComponent(prompt)}`, ); return res.json(); // { params, signature } }, }); ``` This gives you full control over: - Which Transloadit account / key to use. - Which AI model, aspect ratio, and number of outputs to request. - How you structure your `steps` (as long as they use 🤖 `/image/generate`). --- Source: https://uppy.io/docs/angular # Angular [Angular][] components for Uppy UI plugins. ## When should I use it? When you are using the Angular framework and you would like to use one of the UI components. ## Install **NPM** ```shell npm install @uppy/angular ``` **Yarn** ```shell yarn add @uppy/angular ``` `@uppy/angular` supports Angular 17, 18, 19, 20, 21 and 22. :::note You also need to install the UI plugin you want to use. For instance, `@uppy/dashboard`. ::: To send files to Transloadit, follow the canonical [Angular + Uppy + Transloadit guide](/docs/guides/uppy-transloadit#angular). It includes the required server-side signing boundary. ## Use Instead of adding a UI plugin to an Uppy instance with `.use()`, the Uppy instance can be passed into components as a `props` prop. The following plugins are available as Angular component wrappers: - Import `UppyAngularDashboardModule` used as `` renders [`@uppy/dashboard`](/docs/dashboard) - Import `UppyAngularDashboardModalModule` used as `` renders [`@uppy/dashboard`](/docs/dashboard) as a modal - Import `UppyAngularStatusBarModule` used as `` renders [`@uppy/status-bar`](/docs/status-bar) :::note `UppyAngularDragDropModule` and `UppyAngularProgressBarModule` were removed in Uppy 5.0. The [`@uppy/drag-drop`](/docs/drag-drop) plugin is still supported and can be used directly with `uppy.use(DragDrop, { target })`. ::: Each component takes a `props` prop that will be passed to the UI Plugin. ```typescript title="app.module.ts" showLineNumbers import { NgModule } from '@angular/core'; import { UppyAngularDashboardModule } from '@uppy/angular'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule, UppyAngularDashboardModule], providers: [], bootstrap: [AppComponent], }) class {} ``` ```html title="app.component.html" showLineNumbers ``` You should initialize Uppy as a property of your component. ```typescript title="app.component.ts" showLineNumbers import { Component } from '@angular/core'; import { Uppy } from '@uppy/core'; @Component({ selector: 'app-root', }) export class AppComponent { uppy: Uppy = new Uppy({ debug: true, autoProceed: true }); } ``` ### CSS All components have their own styling and should be added to your component decorator. You can find the CSS import statements in the docs of the UI plugin you want to use. For instance, for `@uppy/dashboard`: ```typescript import { Component, ViewEncapsulation } from '@angular/core'; //... @Component({ // ... encapsulation: ViewEncapsulation.None, styleUrls: [ '../node_modules/@uppy/core/css/style.css', '../node_modules/@uppy/dashboard/css/style.css', ], }) ``` [angular]: https://angular.io --- Source: https://uppy.io/docs/audio # Audio The `@uppy/audio` plugin lets you record audio using a built-in or external microphone, or any other audio device, on desktop and mobile. The UI shows real time sound wavelength when recording. :::tip [Try out the live example](/examples) or take it for a spin in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-zaqyaf?file=main.js). ::: ## When should I use this? When you want users to record audio on their computer. ## Install **NPM** ```shell npm install @uppy/audio ``` **Yarn** ```shell yarn add @uppy/audio ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js {3,7,11} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import Audio from '@uppy/audio'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; import '@uppy/audio/css/style.min.css'; new Uppy().use(Dashboard, { inline: true, target: 'body' }).use(Audio); ``` ### API ### Options #### `id` A unique identifier for this plugin (`string`, default: `'audio'`). #### `title` Configures the title / name shown in the UI, for instance, on Dashboard tabs (`string`, default: `'Audio'`). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `showAudioSourceDropdown` Configures whether to show a dropdown to select audio device (`boolean`, default: `false`). #### `locale` ```js export default { strings: { pluginNameAudio: 'Audio', // Used as the label for the button that starts an audio recording. // This is not visibly rendered but is picked up by screen readers. startAudioRecording: 'Begin audio recording', // Used as the label for the button that stops an audio recording. // This is not visibly rendered but is picked up by screen readers. stopAudioRecording: 'Stop audio recording', // Title on the “allow access” screen allowAudioAccessTitle: 'Please allow access to your microphone', // Description on the “allow access” screen allowAudioAccessDescription: 'In order to record audio, please allow microphone access for this site.', // Title on the “device not available” screen noAudioTitle: 'Microphone Not Available', // Description on the “device not available” screen noAudioDescription: 'In order to record audio, please connect a microphone or another audio input device', // Message about file size will be shown in an Informer bubble recordingStoppedMaxSize: 'Recording stopped because the file size is about to exceed the limit', // Used as the label for the counter that shows recording length (`1:25`). // This is not visibly rendered but is picked up by screen readers. recordingLength: 'Recording length %{recording_length}', // Used as the label for the submit checkmark button. // This is not visibly rendered but is picked up by screen readers. submitRecordedFile: 'Submit recorded file', // Used as the label for the discard cross button. // This is not visibly rendered but is picked up by screen readers. discardRecordedFile: 'Discard recorded file', }, }; ``` --- Source: https://uppy.io/docs/aws-s3 # AWS S3 The `@uppy/aws-s3` plugin uploads files from the browser directly to an S3 bucket, or to any S3-compatible service such as Cloudflare R2, MinIO, or DigitalOcean Spaces. Small files are sent in a single request (a presigned `PUT` in the direct modes, a `POST` form upload through Companion), large files as a multipart upload. Every request to S3 has to be signed, and you choose how that happens: | Option | Who signs | What you run | | ------------------- | ---------------------------- | --------------------------------------------------- | | `getCredentials` | the browser, with SigV4 | an endpoint handing out temporary credentials | | `signRequest` | your own code | an endpoint returning a presigned URL per operation | | `companionEndpoint` | [Companion](/docs/companion) | Companion | The three modes are mutually exclusive. Pass exactly one: the plugin throws if you pass none. :::note Upgrading from Uppy 5.x? All signing options changed names and shapes. See the [migration guide](/docs/guides/migration-guides/). ::: ## When should I use it? :::tip Not sure which uploader is best for you? Read “[Choosing the uploader you need](/docs/guides/choosing-uploader)”. ::: Use this plugin when you prefer a _client-to-storage_ over a _client-to-server-to-storage_ (such as [Transloadit](/docs/transloadit) or [Tus](/docs/tus)) setup. This may in some cases be preferable, for instance, to reduce costs or the complexity of running a server and load balancer with [Tus](/docs/tus). Multipart uploads become valuable for larger files, as the object is uploaded as a set of parts. Only failed parts have to be retried, and an interrupted upload can resume where it stopped instead of starting over. The downside is request overhead: creation, signing, and completion requests on top of the upload requests themselves. For a file of a couple of kilobytes with 100 ms roundtrip latency, that overhead is most of the upload. We recommend keeping the default [`shouldUseMultipart`][], which uses multipart only for large files. Which signing mode to pick: - [`signRequest`](#signrequestrequest) keeps your credentials on your server and is the safest default. - [`getCredentials`](#getcredentials) removes one round trip per S3 operation, because the browser signs locally. In exchange, the browser holds credentials that are valid for whatever your policy grants, so scope that policy tightly. - [`companionEndpoint`](#companionendpoint) is worth it if you already run [Companion][companion docs] for remote sources such as Google Drive. ## Install **NPM** ```shell npm install @uppy/aws-s3 ``` **Yarn** ```shell yarn add @uppy/aws-s3 ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use Whichever mode you pick, your bucket needs [CORS rules](#bucket-and-cors-setup). ### Sign on your server Your server returns a presigned URL for each S3 operation, and the browser sends the request to that URL. Credentials never leave your server. ```js {9-18} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import AwsS3 from '@uppy/aws-s3'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy().use(Dashboard, { inline: true, target: 'body' }).use(AwsS3, { async signRequest({ method, key, uploadId, partNumber }) { const response = await fetch('/s3/presign', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ method, key, uploadId, partNumber }), }); if (!response.ok) throw new Error('Failed to sign S3 request'); // The server responds with `{ "url": "https://…" }`, // optionally with a `key` if it stored the object elsewhere return response.json(); }, }); ``` There is no `s3Endpoint` in this mode: the URL you return determines the host, bucket, and object key. See [`signRequest`](#signrequestrequest) for the operations your endpoint has to handle, and the [Node.js example](https://github.com/transloadit/uppy/tree/main/examples/aws-nodejs) for a working `/s3/presign` route built on the AWS SDK. ### Sign on the client Your server hands out short-lived credentials (on AWS, from [STS](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html)), and the browser signs every S3 request itself with SigV4. The credentials are requested once and reused until S3 rejects them as expired. ```js {9-11} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import AwsS3 from '@uppy/aws-s3'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy().use(Dashboard, { inline: true, target: 'body' }).use(AwsS3, { s3Endpoint: 'https://my-bucket.s3.us-east-1.amazonaws.com', region: 'us-east-1', async getCredentials() { const response = await fetch('/s3/sts'); if (!response.ok) throw new Error('Failed to fetch STS credentials'); const { credentials, region } = await response.json(); return { credentials: { accessKeyId: credentials.AccessKeyId, secretAccessKey: credentials.SecretAccessKey, sessionToken: credentials.SessionToken, expiration: credentials.Expiration, }, region, }; }, }); ``` :::caution The credentials are handed to the browser, so the policy you attach to them is the only thing standing between your users and your bucket. Grant the smallest possible set of actions on the smallest possible resource, and keep the lifetime short. Read [Requesting temporary security credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) before using this mode. ::: ### Use with Companion [Companion][companion docs] has S3 routes built in, and signs the uploads with its own bucket configuration. This is also the mode to use for files coming from remote sources such as Google Drive, which Companion uploads server-side. :::caution Generally it’s better for access control, observability, and scaling to integrate `@uppy/aws-s3` with your own server. You may want to use [Companion](/docs/companion) for creating, signing, and completing your S3 uploads if you already need Companion for remote files (such as from Google Drive). Otherwise it’s not worth the hosting effort. ::: ```js {9} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import AwsS3 from '@uppy/aws-s3'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy().use(Dashboard, { inline: true, target: 'body' }).use(AwsS3, { companionEndpoint: 'https://companion.uppy.io', }); ``` Companion decides the bucket, the region, and the object key, so [`s3Endpoint`](#s3endpoint), [`region`](#region), and [`generateObjectKey`](#generateobjectkeyfile) are not used in this mode. ## API ### Options #### `id` A unique identifier for this plugin (`string`, default: `'AwsS3'`). #### `shouldUseMultipart(file)` A boolean, or a function that returns a boolean which is called for each file that is uploaded with the corresponding `UppyFile` instance as argument (`boolean | function`, default: files larger than 100 MiB). ```js uppy.use(AwsS3, { // … shouldUseMultipart(file) { return file.size > 100 * 2 ** 20; }, }); ``` When it returns `true`, the file is uploaded as multipart whatever its size. S3’s 5 MiB minimum part size does not apply to the last part, so a smaller file becomes a multipart upload with a single part. The exception is an empty file, which is always uploaded in a single request, since there is no part to send. #### `limit` The maximum number of files to upload in parallel (`number`, default: `6`). The parts of a single file are uploaded one after the other, so this is also the number of concurrent requests to S3. The default matches the number of connections browsers open per host over HTTP/1.1. #### `getChunkSize(file)` A function that returns the part size in bytes to use when uploading the given file as multipart (`function`, default: the file size divided by 10,000). It receives an object with only a `size` property, not the full Uppy file. S3 requires a minimum part size of 5 MiB and supports at most 10,000 parts per upload. If `getChunkSize()` returns something smaller, or something that would produce more than 10,000 parts, the plugin corrects it. A larger part size means fewer requests, at the cost of re-uploading more data when a part fails. ```js uppy.use(AwsS3, { // … getChunkSize(file) { return Math.max(5 * 2 ** 20, file.size / 1000); }, }); ``` #### `generateObjectKey(file)` A function that returns the object key to store the file under (`function`, default: `` `${crypto.randomUUID()}-${file.name}` ``). ```js uppy.use(AwsS3, { // … generateObjectKey: (file) => `uploads/${Date.now()}-${file.name}`, }); ``` The key generated here is a proposal. With [`signRequest`](#signrequestrequest), your server can store the object under a different key by returning it as `key`. Not used with [`companionEndpoint`](#companionendpoint): Companion generates the key. #### `signRequest(request)` A function that returns a presigned URL for one S3 operation (`function`). Required unless you use [`getCredentials`](#getcredentials) or [`companionEndpoint`](#companionendpoint). It receives an object with: - `method`: `'PUT' | 'POST' | 'GET' | 'DELETE'`, the HTTP method of the request. - `key`: `string`, the object key. - `uploadId`: `string`, only present for multipart operations. - `partNumber`: `number`, only present when uploading a part. It must return a promise for an object with: - `url`: `string`, the presigned URL. - `key`: `string`, optional. The key your server stored the object under. Uppy uses it for the rest of the upload and reports it in `upload-success`. Leave it out if the server used the key Uppy sent. - `headers`: `object`, optional. The headers this URL was signed with, from its `X-Amz-SignedHeaders`, with the values you signed. Uppy sends them with the request. A `Content-Type` here replaces the one Uppy sets from the file’s type. Leave out `host` and `content-length`: the browser sends those itself. Don’t sign headers the browser won’t let JavaScript set, such as `date`, since a URL signed with one can’t be used from a browser. Each header must also be in your bucket’s CORS `AllowedHeaders` (see [Bucket and CORS setup](#bucket-and-cors-setup)). These are the operations your endpoint has to sign: | Request | S3 operation | | ---------------------------------------------- | ----------------------- | | `{ method: 'PUT', key }` | PutObject | | `{ method: 'POST', key }` | CreateMultipartUpload | | `{ method: 'PUT', key, uploadId, partNumber }` | UploadPart | | `{ method: 'GET', key, uploadId }` | ListParts | | `{ method: 'POST', key, uploadId }` | CompleteMultipartUpload | | `{ method: 'DELETE', key, uploadId }` | AbortMultipartUpload | If [`shouldUseMultipart`](#shouldusemultipartfile) is `false` for every file, the first row is the only one you need. To generate the object key on your server instead, change it only on the request that creates the object: the single-part `PUT`, or the `POST` without an `uploadId`. Return the key you used as `key` there. Every request that carries an `uploadId` must be signed for exactly the key it arrives with. That key was fixed when the upload was created, and a `key` returned on those requests is ignored. A server that derives the key again on every request prefixes a key that is already prefixed, and S3 answers with `NoSuchUpload`. The [Node.js](https://github.com/transloadit/uppy/blob/main/examples/aws-nodejs/routes/presign.js) and [PHP](https://github.com/transloadit/uppy/blob/main/examples/aws-php/s3-sign.php) signer examples show how to do this correctly. The same goes for `headers`: return only what that request was signed with. `Content-Disposition` and `Content-Type` belong on the request that creates the object. Returning them on every request sends them where they were not signed, and a `Content-Type` on the `POST` that completes a multipart upload replaces the `application/xml` Uppy needs there. #### `getCredentials()` A function that returns temporary security credentials for client-side signing (`function`). Required, together with [`s3Endpoint`](#s3endpoint), unless you use [`signRequest`](#signrequestrequest) or [`companionEndpoint`](#companionendpoint). It must return an object (or a promise for one) with: - `credentials`: `object` - `accessKeyId`: `string` - `secretAccessKey`: `string` - `sessionToken`: `string` - `expiration`: `string`, optional ISO 8601 date. - `region`: `string`, the region to sign for. Takes precedence over [`region`](#region). The result is cached for the lifetime of the plugin, so your endpoint is hit once instead of once per request. When S3 answers with `ExpiredToken` or `InvalidAccessKeyId`, the plugin drops the cache, calls `getCredentials()` again, and retries the request once. AWS STS returns `AccessKeyId`, `SecretAccessKey`, and `SessionToken` in PascalCase; map them to the camelCase keys above, as in the [example](#sign-on-the-client). #### `s3Endpoint` The URL of the bucket to upload to (`string`). Required with [`getCredentials`](#getcredentials), unused in the other modes. Both the virtual-hosted style (`https://my-bucket.s3.us-east-1.amazonaws.com`) and the path style (`https://s3.us-east-1.amazonaws.com/my-bucket`) work. The object key is appended to it. #### `region` The region to sign requests for (`string`, default: `'auto'`). Used with [`getCredentials`](#getcredentials), and overridden by the `region` that `getCredentials()` returns. `'auto'` is what S3-compatible services that have no regions, such as Cloudflare R2, expect. AWS S3 needs the real region of the bucket. #### `companionEndpoint` The URL of your [Companion][companion docs] instance (`string`). Required unless you use [`signRequest`](#signrequestrequest) or [`getCredentials`](#getcredentials). #### `allowedMetaFields` Pass an array of field names to limit the metadata fields that are sent to Companion, which stores them as S3 object metadata (`boolean | Array`, default: `true`). - Set it to `false` to not send any fields (or an empty array). - Set it to `['name']` to only send the `name` field. - Set it to `true` (the default) to send _all_ metadata fields. :::note Object metadata is only sent in the [Companion](#companionendpoint) mode. The two direct signing modes upload the file contents and nothing else. ::: ## S3-compatible services Any service that speaks the S3 API works in every signing mode. For [`signRequest`](#signrequestrequest) there is nothing to configure, as your signer decides the host. For [`getCredentials`](#getcredentials), point [`s3Endpoint`](#s3endpoint) at the service and set the [`region`](#region) it expects. Cloudflare R2: ```js uppy.use(AwsS3, { s3Endpoint: 'https://.r2.cloudflarestorage.com/my-bucket', region: 'auto', getCredentials, }); ``` MinIO, or another self-hosted service: ```js uppy.use(AwsS3, { s3Endpoint: 'https://minio.my-app.com/my-bucket', region: 'us-east-1', getCredentials, }); ``` ## Bucket and CORS setup S3 buckets do not allow public uploads for security reasons. To allow Uppy and the browser to upload directly to a bucket, its CORS permissions need to be configured. CORS permissions can be found in the [S3 Management Console](https://console.aws.amazon.com/s3/home). Click the bucket that will receive the uploads, then go into the `Permissions` tab and select the `CORS configuration` button. A JSON document will be shown that defines the CORS configuration. (AWS used to use XML but now only allow JSON). More information about the [S3 CORS format here](https://docs.amazonaws.cn/en_us/AmazonS3/latest/userguide/ManageCorsUsing.html). The configuration required for Uppy is this: ```json [ { "AllowedOrigins": ["https://my-app.com"], "AllowedMethods": ["GET", "PUT", "POST", "DELETE"], "MaxAgeSeconds": 3000, "AllowedHeaders": ["content-type"], "ExposeHeaders": ["ETag", "Location"] }, { "AllowedOrigins": ["*"], "AllowedMethods": ["GET"], "MaxAgeSeconds": 3000 } ] ``` A good practice is to use two CORS rules: one for uploading files (the first object in the array) and one for viewing them from the browser (the second). CORS only controls which origins the browser lets read the responses. Whether an object can be viewed at all is decided by your bucket policy and ACLs, not by this rule. `ExposeHeaders` has to include `ETag`, or multipart uploads cannot be completed: the browser needs to read the `ETag` of every part it uploads. `DELETE` is used to abort a multipart upload when the user cancels one, and `GET` to list the parts of an upload that is being resumed. `AllowedHeaders` has to list every header Uppy sets on the request. That is `content-type`, plus any header your [`signRequest`](#signrequestrequest) returns, such as `content-disposition`. A header missing here fails the CORS preflight before the upload starts. If you are using an IAM policy to allow access to the S3 bucket, the policy needs at least the `s3:PutObject`, `s3:ListMultipartUploadParts` (listing parts when an upload resumes), and `s3:AbortMultipartUpload` (cancelling an upload) permissions scoped to the bucket in question. Add `s3:PutObjectAcl` only if you configure an ACL on uploads. In-depth documentation about CORS rules is available on the [AWS documentation site](https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html). ## Use with TypeScript Uppy always puts the response to an upload in `file.response.body`. If you want this to be type safe with `@uppy/aws-s3`, you can import the `AwsBody` type and pass it as the second generic to `Uppy`. ```ts {3,12} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import AwsS3, { type AwsBody } from '@uppy/aws-s3'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; // Set this to `any` or `Record` // if you do not set any metadata yourself type Meta = { license: string }; const uppy = new Uppy() .use(Dashboard, { inline: true, target: 'body' }) .use(AwsS3, { companionEndpoint: 'https://companion.uppy.io' }); const id = uppy.addFile(/* … */); await uppy.upload(); const body = uppy.getFile(id).response.body!; const { location, key } = body; // This is now type safe ``` [`shouldusemultipart`]: #shouldusemultipartfile [companion docs]: /docs/companion --- Source: https://uppy.io/docs/box # Box The `@uppy/box` plugin lets users import files from their [Box](https://www.box.com/en-nl/home) account. :::tip [Try out the live example](/examples) or take it for a spin in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-zaqyaf?file=main.js). ::: ## When should I use this? When you want to let users import files from their [Box](https://www.box.com/en-nl/home) account. A [Companion](/docs/companion) instance is required for the Box plugin to work. Companion handles authentication with Box, downloads the files, and uploads them to the destination. This saves the user bandwidth, especially helpful if they are on a mobile connection. You can self-host Companion or get a hosted version with any [Transloadit plan](https://transloadit.com/pricing/). **NPM** ```shell npm install @uppy/box ``` **Yarn** ```shell yarn add @uppy/box ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use Using Box requires setup in both Uppy and Companion. ### Use in Uppy ```js {10-13} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import Box from '@uppy/box'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(Box, { companionUrl: 'https://your-companion.com' }); ``` ### Use with Transloadit ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Box from '@uppy/box'; uppy.use(Box, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }); ``` You may also hit rate limits, because the OAuth application is shared between everyone using Transloadit. To solve that, you can use your own OAuth keys with Transloadit’s hosted Companion servers by using Transloadit Template Credentials. [Create a Template Credential][template-credentials] on the Transloadit site. Select “Companion OAuth” for the service, and enter the key and secret for the provider you want to use. Then you can pass the name of the new credentials to that provider: ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Box from '@uppy/box'; uppy.use(Box, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'my_companion_dropbox_creds', }, }); ``` ### Use in Companion You can create a Box App on the [Box Developers site](https://app.box.com/developers/console). Things to note: - Choose `Custom App` and select the `User Authentication (OAuth 2.0)` app type. - You must enable full write access, or you will get [403 when downloading files](https://support.box.com/hc/en-us/community/posts/360049195613-403-error-while-file-download-API-Call) You’ll be redirected to the app page. This page lists the client ID (app key) and client secret (app secret), which you should use to configure Companion. The app page has a `"Redirect URIs"` field. Here, add: ``` https://$YOUR_COMPANION_HOST_NAME/box/redirect ``` If you are using Transloadit hosted Companion: ``` https://api2.transloadit.com/companion/box/redirect ``` You can only use the integration with your own account initially. Make sure to apply for production status on the app page before you publish your app, or your users will not be able to sign in! Configure the Box key and secret. With the standalone Companion server, specify environment variables: ```shell export COMPANION_BOX_KEY="Box API key" export COMPANION_BOX_SECRET="Box API secret" ``` When using the Companion Node.js API, configure these options: ```js companion.app({ providerOptions: { box: { key: 'Box API key', secret: 'Box API secret', }, }, }); ``` ## API ### Options #### `id` A unique identifier for this plugin (`string`, default is a unique ID for each plugin). #### `title` Title / name shown in the UI, such as Dashboard tabs (`string`, default is the name of the plugin). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `companionUrl` URL to a [Companion](/docs/companion) instance (`string`, default: `null`). For Transloadit-hosted Companion use the `COMPANION_URL` constant exported by `@uppy/transloadit`, which is `https://api2.transloadit.com/companion`. Do not use a regional hostname such as `api2-eu-west-1.transloadit.com`: the OAuth flow then starts on one host and returns to another, and login fails with “Cannot find state in session”. #### `companionHeaders` Custom headers that should be sent along to [Companion](/docs/companion) on every request (`Object`, default: `{}`). #### `companionAllowedHosts` The valid and authorised URL(s) from which OAuth responses should be accepted (`string` or `RegExp` or `Array`). This option is useful when you have your [Companion](/docs/companion) running on several hosts. Otherwise, the default value should do fine, which uses the origin of `companionUrl`. This value can be a `string`, a `RegExp` pattern, or an `Array` of these. Strings are evaluated as regular expressions too and will be wrapped in a RegExp like so: ```js new RegExp(`^${value}$`); ``` **Important:** You must escape regex characters like `.`, or you might open your app up to security vulnerabilities. - Example correct strings - `'^(?:.*\\.)?example\.com$'` matches `example.com` and all of its subdomains. - `'https://example\.com'` matches `https://example.com` only. - Example vulnerability: `'https://www.example.com'` would allow an attacker with the domain `wwwxexample.com` to forge and inject a fraudulent token into Uppy. #### `companionKeysParams` Only applies to plugins that sign in through Companion (Google Drive, Dropbox, Box, OneDrive, …). The Google Drive Picker and Google Photos Picker ignore it; they authenticate directly with Google. Google Drive Picker uses its own `clientId`, `apiKey` and `appId`, while Google Photos Picker uses its own `clientId`. Use your own OAuth app with Transloadit-hosted Companion instead of Transloadit’s shared one (`Object`, default: `undefined`). It has two fields: - `key`: your Transloadit API key. - `credentialsName`: the name of a “Companion OAuth” credential you created in the Transloadit console, which holds the provider’s OAuth key and secret. ```js companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', } ``` Before the login popup opens, the plugin sends these values to Companion to obtain a pre-auth token, and Companion fetches the OAuth key and secret from Transloadit when the flow starts. The values are also sent along with every later request in a `uppy-credentials-params` header. Companion does not validate the credential name up front, so a wrong name only fails when a user tries to sign in. On Transloadit-hosted Companion this option is required for Google Drive, see [Google Drive: Use with Transloadit](/docs/google-drive#use-with-transloadit). #### `companionCookiesRule` This option correlates to the [RequestCredentials value](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials) (`string`, default: `'same-origin'`). This tells the plugin whether to send cookies to [Companion](/docs/companion). #### `locale` An object with `strings` property containing additional i18n strings. The key is the i18n key and the value is the English string. Example: ```js { strings: { someKey: 'Some English string', }, } ``` #### `storage` A custom storage to be used for the plugin’s persistent data. Type `AsyncStore`, default is `LocalStorage`. [template-credentials]: https://transloadit.com/docs/topics/template-credentials/ --- Source: https://uppy.io/docs/guides/building-plugins # Building plugins You can find already a few useful Uppy plugins out there, but there might come a time when you will want to build your own. Plugins can hook into the upload process or render a custom UI, typically to: - Render some custom UI element, such as [StatusBar](/docs/status-bar) or [Dashboard](/docs/dashboard). - Do the actual uploading, such as [XHRUpload](/docs/xhr-upload) or [Tus](/docs/tus). - Do work before the upload, like compressing an image or calling external API. - Interact with a third-party service to process uploads correctly, such as [Transloadit](/docs/transloadit) or [AwsS3](/docs/aws-s3). See a [full example of a plugin](#example-of-a-custom-plugin) below. ## Creating A Plugin Uppy has two classes to create plugins with. `BasePlugin` for plugins that don’t need a user interface, and `UIPlugin` for ones that do. Each plugin has an `id` and a `type`. `id`s are used to uniquely identify plugins. A `type` can be anything. Some plugins use `type`s to decide whether to do something to some other plugin. For example, when targeting plugins at the built-in `Dashboard` plugin, the Dashboard uses the `type` to figure out where to mount different UI elements. `'acquirer'`-type plugins are mounted into the tab bar, while `'progressindicator'`-type plugins are mounted into the progress bar area. The plugin constructor receives the Uppy instance in the first parameter, and any options passed to `uppy.use()` in the second parameter. ```js import BasePlugin from '@uppy/core'; export default class MyPlugin extends BasePlugin { constructor(uppy, opts) { super(uppy, opts); this.id = opts.id || 'MyPlugin'; this.type = 'example'; } } ``` ## Methods Plugins can define methods to execute certain tasks. The most important method is `install()`, which is called when a plugin is `.use`d. All the below methods are optional! Only define the methods you need. ### `BasePlugin` #### `install()` Called when the plugin is `.use`d. Do any setup work here, like attaching events or adding [upload hooks](#upload-hooks). ```js export default class MyPlugin extends UIPlugin { // ... install() { this.uppy.on('upload-progress', this.onProgress); this.uppy.addPostProcessor(this.afterUpload); } } ``` #### `uninstall()` Called when the plugin is removed, or the Uppy instance is closed. This should undo all the work done in the `install()` method. ```js export default class MyPlugin extends UIPlugin { // ... uninstall() { this.uppy.off('upload-progress', this.onProgress); this.uppy.removePostProcessor(this.afterUpload); } } ``` #### `afterUpdate()` Called after every state update with a debounce, after everything has mounted. #### `addTarget()` Use this to add your plugin to another plugin’s target. This is what `@uppy/dashboard` uses to add other plugins to its UI. ### `UIPlugin` `UIPlugin` extends the `BasePlugin` class so it will also contain all the above methods. #### `mount(target)` Mount this plugin to the `target` element. `target` can be a CSS query selector, a DOM element, or another Plugin. If `target` is a Plugin, the source (current) plugin will register with the target plugin, and the latter can decide how and where to render the source plugin. This method can be overridden to support for different render engines. #### `render()` Render this plugin’s UI. Uppy uses [Preact](https://preactjs.com) as its view engine, so `render()` should return a Preact element. `render` is automatically called by Uppy on each state change. #### `onMount()` Called after Preact has rendered the components of the plugin. #### `update(state)` Called on each state update. You will rarely need to use this, unless if you want to build a UI plugin using something other than Preact. #### `onUnmount()` Called after the elements have been removed from the DOM. Can be used to do some clean up or other side-effects. ## Upload Hooks When creating an upload, Uppy runs files through an upload pipeline. The pipeline consists of three parts, each of which can be hooked into: Preprocessing, Uploading, and Postprocessing. Preprocessors can be used to configure uploader plugins, encrypt files, resize images, etc., before uploading them. Uploaders do the actual uploading work, such as creating an XMLHttpRequest object and sending the file. Postprocessors do their work after files have been uploaded completely. This could be anything from waiting for a file to propagate across a CDN, to sending another request to relate some metadata to the file. Each hook is a function that receives an array containing the file IDs that are being uploaded, and returns a Promise to signal completion. Hooks are added and removed through `Uppy` methods: [`addPreProcessor`](/docs/uppy#addpreprocessorfn), [`addUploader`](/docs/uppy#adduploaderfn), [`addPostProcessor`](/docs/uppy#addpostprocessorfn), and their [`remove*`](/docs/uppy#removepreprocessorremoveuploaderremovepostprocessorfn) counterparts. Normally, hooks should be added during the plugin `install()` method, and removed during the `uninstall()` method. Additionally, upload hooks can fire events to signal progress. When adding hooks, make sure to bind the hook `fn` beforehand! Otherwise, it will be impossible to remove. For example: ```js class MyPlugin extends BasePlugin { constructor(uppy, opts) { super(uppy, opts); this.id = opts.id || 'MyPlugin'; this.type = 'example'; this.prepareUpload = this.prepareUpload.bind(this); // ← this! } prepareUpload(fileIDs) { console.log(this); // `this` refers to the `MyPlugin` instance. return Promise.resolve(); } install() { this.uppy.addPreProcessor(this.prepareUpload); } uninstall() { this.uppy.removePreProcessor(this.prepareUpload); } } ``` Or you can define the method as a class field: ```js class MyPlugin extends UIPlugin { constructor(uppy, opts) { super(uppy, opts); this.id = opts.id || 'MyPlugin'; this.type = 'example'; } prepareUpload = (fileIDs) => { // ← this! console.log(this); // `this` refers to the `MyPlugin` instance. return Promise.resolve(); }; install() { this.uppy.addPreProcessor(this.prepareUpload); } uninstall() { this.uppy.removePreProcessor(this.prepareUpload); } } ``` ## Progress events Progress events can be fired for individual files to show feedback to the user. For upload progress events, only emitting how many bytes are expected and how many have been uploaded is enough. Uppy will handle calculating progress percentages, upload speed, etc. Preprocessing and postprocessing progress events are plugin-dependent and can refer to anything, so Uppy doesn’t try to be smart about them. Processing progress events can be of two types: determinate or indeterminate. Some processing does not have meaningful progress beyond “not done” and “done”. For example, sending a request to initialize a server-side resource that will serve as the upload destination. In those situations, indeterminate progress is suitable. Other processing does have meaningful progress. For example, encrypting a large file. In those situations, determinate progress is suitable. Here are the relevant events: - [`preprocess-progress`](/docs/uppy#preprocess-progress) - [`upload-progress`](/docs/uppy#upload-progress) - [`postprocess-progress`](/docs/uppy#postprocess-progress) ## JSX Since Uppy uses Preact and not React, the default Babel configuration for JSX elements does not work. You have to import the Preact `h` function and tell Babel to use it by adding a `/** @jsx h */` comment at the top of the file. See the Preact [Getting Started Guide](https://preactjs.com/guide/getting-started) for more on Babel and JSX. ```jsx /** @jsx h */ import { UIPlugin } from '@uppy/core'; import { h } from 'preact'; class NumFiles extends UIPlugin { render() { const numFiles = Object.keys(this.uppy.state.files).length; return
Number of files: {numFiles}
; } } ``` ## Locales For any user facing language that you use while writing your Plugin, please provide them as strings in the `defaultLocale` property like so: ```js this.defaultLocale = { strings: { youCanOnlyUploadFileTypes: 'You can only upload: %{types}', youCanOnlyUploadX: { 0: 'You can only upload %{smart_count} file', 1: 'You can only upload %{smart_count} files', 2: 'You can only upload %{smart_count} files', }, }, }; ``` This allows them to be overridden by Locale Packs, or directly when users pass `locale: { strings: youCanOnlyUploadFileTypes: 'Something else completely about %{types}'} }`. For this to work, it’s also required that you call `this.i18nInit()` in the plugin constructor. ## Example of a custom plugin Below is a full example of a [small plugin](https://github.com/arturi/uppy-plugin-image-compressor) that compresses images before uploading them. You can replace `compressorjs` method with any other work you need to do. This works especially well for async stuff, like calling an external API. ```js import { UIPlugin } from '@uppy/core'; import { Translator } from '@uppy/core/utils'; import Compressor from 'compressorjs/dist/compressor.esm.js'; class UppyImageCompressor extends UIPlugin { constructor(uppy, opts) { const defaultOptions = { quality: 0.6, }; super(uppy, { ...defaultOptions, ...opts }); this.id = this.opts.id || 'ImageCompressor'; this.type = 'modifier'; this.defaultLocale = { strings: { compressingImages: 'Compressing images...', }, }; // we use those internally in `this.compress`, so they // should not be overridden delete this.opts.success; delete this.opts.error; this.i18nInit(); } compress(blob) { return new Promise( (resolve, reject) => new Compressor(blob, { ...this.opts, success(result) { return resolve(result); }, error(err) { return reject(err); }, }), ); } prepareUpload = (fileIDs) => { const promises = fileIDs.map((fileID) => { const file = this.uppy.getFile(fileID); this.uppy.emit('preprocess-progress', file, { mode: 'indeterminate', message: this.i18n('compressingImages'), }); if (!file.type.startsWith('image/')) { return; } return this.compress(file.data) .then((compressedBlob) => { this.uppy.log( `[Image Compressor] Image ${file.id} size before/after compression: ${file.data.size} / ${compressedBlob.size}`, ); this.uppy.setFileState(fileID, { data: compressedBlob }); }) .catch((err) => { this.uppy.log( `[Image Compressor] Failed to compress ${file.id}:`, 'warning', ); this.uppy.log(err, 'warning'); }); }); const emitPreprocessCompleteForAll = () => { fileIDs.forEach((fileID) => { const file = this.uppy.getFile(fileID); this.uppy.emit('preprocess-complete', file); }); }; // Why emit `preprocess-complete` for all files at once, instead of // above when each is processed? // Because it leads to StatusBar showing a weird “upload 6 files” button, // while waiting for all the files to complete pre-processing. return Promise.all(promises).then(emitPreprocessCompleteForAll); }; install() { this.uppy.addPreProcessor(this.prepareUpload); } uninstall() { this.uppy.removePreProcessor(this.prepareUpload); } } export default UppyImageCompressor; ``` --- Source: https://uppy.io/docs/guides/building-your-own-ui-with-uppy # Building your own UI with Uppy :::note This guide is in progress. ::: If you want to use Uppy with your own UI, you would have to instantiate the `Uppy` class and call methods on this instance as well as hook into events in order to react to changes in Uppy. See [Uppy core](/docs/uppy/) and [React](https://github.com/transloadit/uppy/tree/main/examples/react), [Vue](https://github.com/transloadit/uppy/tree/main/examples/vue) and [Svelte](https://github.com/transloadit/uppy/tree/main/examples/sveltekit) examples. --- Source: https://uppy.io/docs/guides/choosing-uploader # Choosing the uploader you need Versatile, reliable uploading is at the heart of Uppy. It has many configurable plugins to suit your needs. In this guide we will explain the different plugins, their strategies, and when to use them based on use cases. ## Use cases ### I want worry-free, plug-and-play uploads with Transloadit services Transloadit’s strength is versatility. By doing video, audio, images, documents, and more, you only need one vendor for [all your file processing needs][transloadit-services]. The [`@uppy/transloadit`][] plugin directly uploads to Transloadit so you only have to worry about creating a [template][transloadit-concepts]. It uses [Tus](#i-want-reliable-resumable-uploads) under the hood so you don’t have to sacrifice reliable, resumable uploads for convenience. You should use [`@uppy/transloadit`][] if you don’t want to host your own server, (optionally) need file processing, and store it in the service (such as S3 or GCS) of your liking. All with minimal effort. ### I want reliable, resumable uploads [Tus][tus] is a new open protocol for resumable uploads built on HTTP. This means accidentally closing your tab or losing connection let’s you continue, for instance, your 10GB upload instead of starting all over. Tus supports any language, any platform, and any network. It requires a client and server integration to work. You can checkout the client and server [implementations][tus-implementations] to find the server in your preferred language. You can store files on the Tus server itself, but you can also use service integrations (such as S3) to store files externally. If you want reliable, resumable uploads: use [`@uppy/tus`][] to connect to your Tus server in a few lines of code. :::tip If you plan to let people upload _a lot_ of files, [`@uppy/tus`][] has exponential backoff built-in. Meaning if your server (or proxy) returns HTTP 429 because it’s being overloaded, [`@uppy/tus`][] will find the ideal sweet spot to keep uploading without overloading. ::: ### I want to upload to AWS S3 (or S3-compatible storage) directly When you prefer a _client-to-storage_ over a _client-to-server-to-storage_ (such as [Transloadit](/docs/transloadit) or [Tus](/docs/tus)) setup. This may in some cases be preferable, for instance, to reduce costs or the complexity of running a server and load balancer with [Tus](/docs/tus). Uppy has the [`@uppy/aws-s3`][] plugin for this. It supports both multipart and non-multipart uploads (controlled by the `shouldUseMultipart` option. :::info You can also save files in S3 with the [`/s3/store`][s3-robot] robot while still using the powers of Transloadit services. ::: ### I want to send regular HTTP uploads to my own server [`@uppy/xhr-upload`][] handles classic HTML multipart form uploads as well as uploads using the HTTP `PUT` method. [s3-robot]: https://transloadit.com/services/file-exporting/s3-store/ [transloadit-services]: https://transloadit.com/services/ [transloadit-concepts]: https://transloadit.com/docs/getting-started/concepts/ [`@uppy/transloadit`]: /docs/transloadit [`@uppy/tus`]: /docs/tus [`@uppy/aws-s3`]: /docs/aws-s3 [`@uppy/xhr-upload`]: /docs/xhr-upload [tus]: https://tus.io/ [tus-implementations]: https://tus.io/implementations.html --- Source: https://uppy.io/docs/companion # Companion Companion is an open source server application which **takes away the complexity of authentication and the cost of downloading files from remote sources**, such as Google Drive, Dropbox, and others. Companion is a server-to-server orchestrator that streams files from a source to a destination, and files are never stored in Companion. Companion can run either as a standalone (self-hosted) application, [Transloadit-hosted](#hosted), or plugged in as an Express middleware into an existing application. The Uppy client requests remote files from Companion, which it will download and simultaneously upload to your [Tus server](/docs/tus), [AWS bucket](/docs/aws-s3), or any server that supports [PUT, POST or Multipart uploads](/docs/xhr-upload). This means a user uploading a 5GB video from Google Drive from their phone isn’t eating into their data plans and you don’t have to worry about implementing OAuth. ## When should I use it? If you want to let users download files from [Box][], [Dropbox][], [Facebook][], [Google Drive][googledrive], [Google Drive Picker][googledrivepicker], [Google Photos Picker][googlephotospicker], [OneDrive][], [Unsplash][], [Import from URL][url], or [Zoom][], you need Companion. Companion supports the same [uploaders](/docs/guides/choosing-uploader) as Uppy: [Tus](/docs/tus), [AWS S3](/docs/aws-s3), and [regular multipart](/docs/tus). But instead of manually setting a plugin, Uppy sends along a header with the uploader and Companion will use the same on the server. This means if you are using [Tus](/docs/tus) for your local uploads, you can send your remote uploads to the same Tus server (and likewise for your AWS S3 bucket). :::note Companion only deals with _remote_ files, _local_ files are still uploaded from the client with your upload plugin. ::: ## Hosted Using [Transloadit][] services comes with a hosted version of Companion so you don’t have to worry about hosting your own server. Whether you are on a free or paid Transloadit [plan](https://transloadit.com/pricing/), you can use Companion. It’s not possible to rent a Companion server without a Transloadit plan. [**Sign-up for a (free) plan**](https://transloadit.com/pricing/). :::tip Choosing Transloadit for your file services also comes with temporary credentials for most remote providers, so you can get started without going through each provider’s app approval process. Google Drive is the exception, see below. When you’re ready, we still expect you to add your own credentials to prevent rate limits across our customers. ::: :::warning Google Drive needs your own Google OAuth app Transloadit’s shared Google OAuth app is blocked by Google, so the [Google Drive](/docs/google-drive) plugin does not work on hosted Companion with the default credentials. Users get a Google page that says “This app is blocked”. Register your own Google OAuth app and store it as a Transloadit credential as described in [Use with Transloadit](/docs/google-drive#use-with-transloadit), or use the [Google Drive Picker](/docs/google-drive-picker) plugin instead. ::: :::info Downloading and uploading files through Companion doesn’t count towards your [monthly quota](https://transloadit.com/docs/faq/1gb-worth/), it’s a way for files to arrive at Transloadit servers, much like Uppy. ::: To do so each provider plugin must be configured with Transloadit’s Companion URLs: ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Dropbox from '@uppy/dropbox'; uppy.use(Dropbox, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }); ``` You may also hit rate limits, because the OAuth application is shared between everyone using Transloadit. To solve that, you can use your own OAuth keys with Transloadit’s hosted Companion servers. [Create a credential][template-credentials] on the Transloadit site (the console calls them Third-party Credentials). Select “Companion OAuth” for the service, pick the provider, and enter the key and secret. Then pass the name of the credential to that provider plugin together with your Transloadit API key: ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Dropbox from '@uppy/dropbox'; uppy.use(Dropbox, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'my_companion_dropbox_creds', }, }); ``` ## Installation & use Companion is installed from npm. Depending on how you want to run Companion, the install process is slightly different. Companion can be integrated as middleware into your [Express](https://expressjs.com/) app or as a standalone server. Most people probably want to run it as a standalone server, while the middleware could be used to further customise Companion or integrate it into your own HTTP server code. :::note Companion 7 requires Node.js `>=22.0.0`. Windows is not a supported platform right now. It may work, and we’re happy to accept improvements in this area, but we can’t provide support. ::: ### Standalone mode You can use the standalone version if you want to run Companion as it’s own Node.js process. It’s a configured Express server with sessions, logging, and security best practices. First you’ll typically want to install it globally: ```bash npm install -g @uppy/companion ``` Standalone Companion will always serve HTTP (not HTTPS) and expects a reverse proxy with SSL termination in front of it when running in production. See [`COMPANION_PROTOCOL`](#server) for more information. Companion ships with an executable file (`bin/companion`) which is the standalone server. Unlike the middleware version, options are set via environment variables. :::info Checkout [options](#options) for the available options in JS and environment variable formats. ::: You need at least these three to get started: ```bash export COMPANION_SECRET="shh!Issa Secret!" export COMPANION_DOMAIN="YOUR SERVER DOMAIN" export COMPANION_DATADIR="PATH/TO/DOWNLOAD/DIRECTORY" ``` Then run: ```bash companion ``` You can also pass in the path to your JSON config file, like so: ```bash companion --config /path/to/companion.json ``` You may also want to run Companion in a process manager like [PM2](https://pm2.keymetrics.io/) to make sure it gets restarted on upon crashing as well as allowing scaling to many instances. ### Express middleware mode Companion 7 is built on Express 5. Mounting Companion into an Express 4 app is no longer supported. First install it into your Node.js project with your favorite package manager: ```bash npm install @uppy/companion ``` To plug Companion into an existing server, call its `.app` method, passing in an [options](#options) object as a parameter. This returns a server instance that you can mount on a route in your Express app. Note: do **not** use the `cors` module in your project, because Companion already includes it. Use the `corsOrigins` Companion option to customise CORS behavior. ```js import express from 'express'; import bodyParser from 'body-parser'; import session from 'express-session'; import * as companion from '@uppy/companion'; const app = express(); // Companion requires body-parser and express-session middleware. // You can add it like this if you use those throughout your app. // // If you are using something else in your app, you can add these // middlewares in the same subpath as Companion instead. app.use(bodyParser.json()); app.use(session({ secret: 'some secrety secret' })); const companionOptions = { secret: 'some secret', // the origin(s) your Uppy app runs on; required corsOrigins: ['https://my-app.com'], // where uploads are allowed to go; required in production uploadUrls: ['https://my-app.com/uploads'], providerOptions: { drive: { key: 'GOOGLE_DRIVE_KEY', secret: 'GOOGLE_DRIVE_SECRET', }, }, server: { host: 'localhost:3020', protocol: 'http', // Default installations normally don't need a path. // However if you specify a `path`, you MUST specify // the same path in `app.use()` below, // e.g. app.use('/companion', companionApp) // path: '/companion', }, filePath: '/path/to/folder/', }; const { app: companionApp } = companion.app(companionOptions); app.use(companionApp); ``` Companion uses WebSockets to communicate progress, errors, and successes to the client. This is what Uppy listens to to update it’s internal state and UI. Add the Companion WebSocket server using the `companion.socket` function: ```js const server = app.listen(PORT); companion.socket(server, companionOptions); ``` :::note As of Companion 7 the second argument is required, and it must be the same options object you passed to `companion.app()`. ::: ### Running many instances We recommend running at least two instances in production, so that if the Node.js event loop gets blocked by one or more requests (due to a bug or spike in traffic), it doesn’t also block or slow down all other requests as well (as Node.js is single threaded). As an example for scale, one enterprise customer of Transloadit, who self-hosts Companion to power an education service that is used by many universities globally, deploys 7 Companion instances. Their earlier solution ran on 35 instances. In our general experience Companion will saturate network interface cards before other resources on commodity virtual servers (`c5d.2xlarge` for instance). Your mileage may vary, so we recommend to add observability. You can let Prometheus crawl the `/metrics` endpoint and graph that with Grafana for instance. #### Using unique endpoints One option is to run many instances with each instance having its own unique endpoint. This could be on separate ports, (sub)domain names, or IPs. With this setup, you can either: 1. Implement your own logic that will direct each upload to a specific Companion endpoint by setting the `companionUrl` option 2. Setting the Companion option `COMPANION_SELF_ENDPOINT`. This option will cause Companion to respond with a `i-am` HTTP header containing the value from `COMPANION_SELF_ENDPOINT`. When Uppy’s sees this header, it will pin all requests for the upload to this endpoint. In either case, you would then also typically configure a single Companion instance (one endpoint) to handle all OAuth authentication requests, so that you only need to specify a single OAuth callback URL. See also `oauthDomain` and `validHosts`. #### Using a load balancer The other option is to set up a load balancer in front of many Companion instances. Then Uppy will only see a single endpoint and send all requests to the associated load balancer, which will then distribute them between Companion instances. The companion instances coordinate their messages and events over Redis so that any instance can serve the client’s requests. Note that sticky sessions are **not** needed with this setup. Here are the requirements for this setup: - The instances need to be connected to the same Redis server. - You need to set `COMPANION_SECRET` to the same value on both servers. - if you use the `companionKeysParams` feature (Transloadit), you also need `COMPANION_PREAUTH_SECRET` to be the same on each instance. - All other configuration needs to be the same, except if you’re running many instances on the same machine, then `COMPANION_PORT` should be different for each instance. ## API ### Options :::tip The headings display the JS and environment variable options (`option` `ENV_OPTION`). When integrating Companion into your own server, you pass the options to `companion.app()`. If you are using the standalone version, you configure Companion using environment variables. Some options only exist as environment variables or only as a JS option. :::
Default configuration ```javascript const options = { server: { protocol: 'http', path: '', }, providerOptions: {}, s3: { endpoint: 'https://{service}.{region}.amazonaws.com', conditions: [], useAccelerateEndpoint: false, getKey: ({ filename }) => `${crypto.randomUUID()}-${filename}`, expires: 800, // seconds }, allowLocalUrls: false, logClientVersion: true, periodicPingUrls: [], streamingUpload: true, clientSocketConnectTimeout: 60000, metrics: true, }; ```
#### `filePath` `COMPANION_DATADIR` Full path to the directory to which provider files will be downloaded temporarily. #### `secret` `COMPANION_SECRET` `COMPANION_SECRET_FILE` A secret string which Companion uses to generate authorization tokens. You should generate a long random string for this. For example: ```js const crypto = require('node:crypto'); const secret = crypto.randomBytes(64).toString('hex'); ``` :::caution Omitting the `secret` in the standalone version will generate a secret for you, using the above `crypto` string. But when integrating with Express you must provide it yourself. This is an essential security measure. ::: :::note Using a secret file means passing an absolute path to a file with any extension, which has only the secret, nothing else. ::: #### `preAuthSecret` `COMPANION_PREAUTH_SECRET` `COMPANION_PREAUTH_SECRET_FILE` If you are using the [Transloadit](/docs/transloadit) `companionKeysParams` feature (Transloadit-hosted Companion using your own custom OAuth credentials), set this variable to a strong randomly generated secret. See also `COMPANION_SECRET` (but do not use the same secret!) :::note Using a secret file means passing an absolute path to a file with any extension, which has only the secret, nothing else. ::: #### `uploadUrls` `COMPANION_UPLOAD_URLS` An allowlist (array) of strings (exact URLs) or regular expressions. Companion will only accept uploads to these URLs. This ensures that your Companion instance is only allowed to upload to your trusted servers and prevents [SSRF](https://en.wikipedia.org/wiki/Server-side_request_forgery) attacks. #### `COMPANION_PORT` The port on which to start the standalone server, defaults to 3020. This is a standalone-only option. #### `COMPANION_COOKIE_DOMAIN` Allows you to customize the domain of the cookies created for Express sessions. This is a standalone-only option. #### `COMPANION_HIDE_WELCOME` Setting this to `true` disables the welcome message shown at `/`. This is a standalone-only option. #### `redisUrl` `COMPANION_REDIS_URL` URL to running Redis server. This can be used to scale Companion horizontally using many instances. See [Running many instances](#running-many-instances). #### `COMPANION_REDIS_EXPRESS_SESSION_PREFIX` Set a custom prefix for redis keys created by [connect-redis](https://github.com/tj/connect-redis). Defaults to `companion-session:`. Sessions are used for storing authentication state and for allowing thumbnails to be loaded by the browser via Companion and for OAuth2. See also `COMPANION_REDIS_PUBSUB_SCOPE`. #### `redisOptions` `COMPANION_REDIS_OPTIONS` An object of [options supported by the `ioredis` client](https://github.com/redis/ioredis). See also [`RedisOptions`](https://github.com/redis/ioredis/blob/af832752040e616daf51621681bcb40cab965a9b/lib/redis/RedisOptions.ts#L8). #### `redisPubSubScope` `COMPANION_REDIS_PUBSUB_SCOPE` Use a scope for the companion events at the Redis server. Setting this option will prefix all events with the name provided and a colon. See also `COMPANION_REDIS_EXPRESS_SESSION_PREFIX`. #### `maxFilenameLength` `COMPANION_MAX_FILENAME_LENGTH` Maximum allowed length for uploaded filenames. Default: 500. If set, it must be set to a value larger than `0`. #### `server` Configuration options for the underlying server. | Key / Environment variable | Value | Description | | ---------------------------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `protocol` `COMPANION_PROTOCOL` | `http` or `https` | Used to build a URL to reference the Companion instance itself, which is used for headers and cookies. Companion itself always runs as a HTTP server, so locally you should use `http`. You must to set this to `https` once you enabled SSL/HTTPS for your domain in production by running a reverse https-proxy in front of Companion, or with a built-in HTTPS feature of your hosting service. | | `host` `COMPANION_DOMAIN` | `String` | Your server’s publicly facing hostname (for example `example.com`). | | `oauthDomain` `COMPANION_OAUTH_DOMAIN` | `String` | If you have several instances of Companion with different (and perhaps dynamic) subdomains, you can set a single fixed subdomain and server (such as `sub1.example.com`) to handle your OAuth authentication for you. This would then redirect back to the correct instance with the required credentials on completion. This way you only need to configure a single callback URL for OAuth providers. | | `path` `COMPANION_PATH` | `String` | The server path to where the Companion app is sitting. For instance, if Companion is at `example.com/companion`, then the path would be `/companion`). | | `implicitPath` `COMPANION_IMPLICIT_PATH` | `String` | If the URL’s path in your reverse proxy is different from your Companion path in your express app, then you need to set this path as `implicitPath`. For instance, if your Companion URL is `example.com/mypath/companion`. Where the path `/mypath` is defined in your NGINX server, while `/companion` is set in your express app. Then you need to set the option `implicitPath` to `/mypath`, and set the `path` option to `/companion`. | | `validHosts` `COMPANION_DOMAINS` | `Array` | If you are setting an `oauthDomain`, you need to set a list of valid hosts, so the oauth handler can validate the host of the Uppy instance requesting the authentication. This is essentially a list of valid domains running your Companion instances. The list may also contain regex patterns. e.g `['sub2.example.com', 'sub3.example.com', '(\\w+).example.com']` | #### `sendSelfEndpoint` `COMPANION_SELF_ENDPOINT` This is essentially the same as the `server.host + server.path` attributes. The major reason for this attribute is that, when set, it adds the value as the `i-am` header of every request response. #### `providerOptions` Object to enable providers with their keys and secrets. For example: ```json { "drive": { "key": "***", "secret": "***" } } ``` When using the standalone version you use the corresponding environment variables or point to a secret file (such as `COMPANION_GOOGLE_SECRET_FILE`). :::note Secret files need an absolute path to a file with any extension which only has the secret, nothing else. ::: | Service | Key | Environment variables | | ------------ | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Box | `box` | `COMPANION_BOX_KEY`, `COMPANION_BOX_SECRET`, `COMPANION_BOX_SECRET_FILE` | | Dropbox | `dropbox` | `COMPANION_DROPBOX_KEY`, `COMPANION_DROPBOX_SECRET`, `COMPANION_DROPBOX_SECRET_FILE` | | Facebook | `facebook` | `COMPANION_FACEBOOK_KEY`, `COMPANION_FACEBOOK_SECRET`, `COMPANION_FACEBOOK_SECRET_FILE` | | Google Drive | `drive` | `COMPANION_GOOGLE_KEY`, `COMPANION_GOOGLE_SECRET`, `COMPANION_GOOGLE_SECRET_FILE` | | OneDrive | `onedrive` | `COMPANION_ONEDRIVE_KEY`, `COMPANION_ONEDRIVE_SECRET`, `COMPANION_ONEDRIVE_SECRET_FILE`, `COMPANION_ONEDRIVE_DOMAIN_VALIDATION` (Settings this variable to `true` enables a route that can be used to validate your app with OneDrive) | | Zoom | `zoom` | `COMPANION_ZOOM_KEY`, `COMPANION_ZOOM_SECRET`, `COMPANION_ZOOM_SECRET_FILE`, `COMPANION_ZOOM_VERIFICATION_TOKEN` | #### `s3` Companion comes with signature endpoints for AWS S3. These can be used by the Uppy client to sign requests to upload files directly to S3, without exposing secret S3 keys in the browser. Companion also supports uploading files from providers like Dropbox and Google Drive directly into S3. ##### `s3.key` `COMPANION_AWS_KEY` The S3 access key ID. ##### `s3.secret` `COMPANION_AWS_SECRET` `COMPANION_AWS_SECRET_FILE` The S3 secret access key. :::note Using a secret file means passing an absolute path to a file with any extension, which has only the secret, nothing else. ::: ##### `s3.endpoint` `COMPANION_AWS_ENDPOINT` Optional URL to a custom S3 (compatible) service. Otherwise uses the default from the AWS SDK. ##### `s3.bucket` `COMPANION_AWS_BUCKET` The name of the bucket to store uploaded files in. A `string` or function that returns the name of the bucket as a `string` and takes one argument which is an object with the following properties: - `filename`, the original name of the uploaded file; - `metadata` provided by the user for the file (will only be provided during the initial calls for each uploaded files, otherwise it will be `undefined`). - `req`, Express.js `Request` object. Do not use any Companion internals from the req object, as these might change in any minor version of Companion. #### `s3.forcePathStyle` `COMPANION_AWS_FORCE_PATH_STYLE` This adds support for setting the S3 client’s `forcePathStyle` option. That is necessary to use Uppy/Companion alongside localstack in development environments. **Default**: `false`. ##### `s3.region` `COMPANION_AWS_REGION` The datacenter region where the target bucket is located. ##### `COMPANION_AWS_PREFIX` An optional prefix for all uploaded keys. This is a standalone-only option. The same can be achieved by the `getKey` option when using the express middleware. ##### `s3.awsClientOptions` You can supply any [S3 option supported by the AWS SDK](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-s3/Interface/S3ClientConfig/) in the `s3.awsClientOptions` object, _except for_ the below: - `accessKeyId`. Instead, use the `s3.key` property. This is to make configuration names consistent between different Companion features. - `secretAccessKey`. Instead, use the `s3.secret` property. This is to make configuration names consistent between different Companion features. Be aware that some options may cause wrong behaviour if they conflict with Companion’s assumptions. If you find that a particular option does not work as expected, please [open an issue on the Uppy repository](https://github.com/transloadit/uppy/issues/new) so we can document it here. ##### `s3.getKey({ filename, metadata, req })` Get the key name for a file. The key is the file path to which the file will be uploaded in your bucket. This option should be a function receiving three arguments: - `filename`, the original name of the uploaded file; - `metadata`, user-provided metadata for the file. - `req`, Express.js `Request` object. Do not use any Companion internals from the req object, as these might change in any minor version of Companion. This function should return a string `key`. The `req` parameter can be used to upload to a user-specific folder in your bucket, for example: ```js app.use(authenticationMiddleware); app.use( uppy.app({ providerOptions: { s3: { getKey: ({ req, filename, metadata }) => `${req.user.id}/${filename}`, /* auth options */ }, }, }), ); ``` The default implementation returns the `filename`, so all files will be uploaded to the root of the bucket as their original file name. ```js app.use( uppy.app({ providerOptions: { s3: { getKey: ({ filename, metadata }) => filename, }, }, }), ); ``` When signing on the client, this function will only be called for multipart uploads. #### `COMPANION_AWS_USE_ACCELERATE_ENDPOINT` Enable S3 [Transfer Acceleration](https://docs.aws.amazon.com/AmazonS3/latest/userguide/transfer-acceleration.html). This is a standalone-only option. #### `COMPANION_AWS_EXPIRES` Set `X-Amz-Expires` query parameter in the presigned urls (in seconds, default: 300\). This is a standalone-only option. #### `COMPANION_AWS_ACL` Set a [Canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl) for uploaded objects. This is a standalone-only option. #### `customProviders` This option enables you to add custom providers along with the already supported providers. See [adding custom providers](#how-to-add-custom-providers) for more information. #### `logClientVersion` A boolean flag to tell Companion whether to log its version upon startup. #### `metrics` `COMPANION_HIDE_METRICS` A boolean flag to tell Companion whether to provide an endpoint `/metrics` with Prometheus metrics (by default metrics are enabled.) #### `streamingUpload` `COMPANION_STREAMING_UPLOAD` A boolean flag to tell Companion whether to enable streaming uploads. If enabled, it will lead to _faster uploads_ because companion will start uploading at the same time as downloading using `stream.pipe`. If `false`, files will be fully downloaded first, then uploaded. Note that for Tus to suppport streaming files of unknown size, this requires an optional extension on the Tus server if using Tus uploads. For form multipart uploads it requres a server that can handle `transfer-encoding: chunked`. Defaults to `true`. #### `maxFileSize` `COMPANION_MAX_FILE_SIZE` If this value is set, companion will limit the maximum file size to process. If unset, it will process files without any size limit (this is the default). #### `periodicPingUrls` `COMPANION_PERIODIC_PING_URLS` If this value is set, companion will periodically send POST requests to the specified URLs. Useful for keeping track of companion instances as a keep-alive. #### `periodicPingInterval` `COMPANION_PERIODIC_PING_INTERVAL` Interval for periodic ping requests (in ms). #### `periodicPingStaticPayload` `COMPANION_PERIODIC_PING_STATIC_JSON_PAYLOAD` A `JSON.stringify`-able JavaScript Object that will be sent as part of the JSON body in the period ping requests. #### `allowLocalUrls` `COMPANION_ALLOW_LOCAL_URLS` A boolean flag to tell Companion whether to allow requesting local URLs (non-internet IPs). :::caution Only enable this in development. **Enabling it in production is a security risk.** ::: #### `corsOrigins` (required) Allowed CORS Origins. Passed as the `origin` option in [cors](https://github.com/expressjs/cors#configuration-options). Note this is used for both CORS’ `Access-Control-Allow-Origin` header, and for the [`targetOrigin`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#targetorigin) for `postMessage` calls in the context of OAuth. Setting it to `true` treats any origin as a trusted one, making it easier to impersonate your brand. Setting it to `false` disables cross-origin support, use this if you’re serving Companion and Uppy from the same domain name. :::note As of Companion 7 the auth token is sent over the WebSocket connection, and `postMessage` is only used as a fallback for Uppy clients older than 6.0. See [How does the Authentication and Token mechanism work?](#how-does-the-authentication-and-token-mechanism-work). The allow-list applies to both paths. ::: ##### `COMPANION_CLIENT_ORIGINS` Stand-alone alternative to the `corsOrigins` option. A comma-separated string of origins, or `'true'` (which will be interpreted as the boolean value `true`), or `'false'` (which will be interpreted as the boolean value `false`). `COMPANION_CLIENT_ORIGINS_REGEX` will be ignored if this option is used. ##### `COMPANION_CLIENT_ORIGINS_REGEX` :::note In most cases, you should not be using a regex, and instead provide the list of accepted origins to `COMPANION_CLIENT_ORIGINS`. If you have to use this option, have in mind that this regex will be used to parse unfiltered user input, so make sure you’re validating the entirety of the string. ::: Stand-alone alternative to the `corsOrigins` option. Like `COMPANION_CLIENT_ORIGINS`, but allows a single regex instead. #### `chunkSize` `COMPANION_CHUNK_SIZE` Controls how big the uploaded chunks are for AWS S3 Multipart and Tus. Smaller values lead to more overhead, but larger values lead to slower retries in case of bad network connections. Passed to tus-js-client [`chunkSize`](https://github.com/tus/tus-js-client/blob/master/docs/api.md#chunksize) as well as [AWS S3 Multipart](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html) `partSize`. #### `enableUrlEndpoint` `COMPANION_ENABLE_URL_ENDPOINT` Set this to `true` to enable the [URL functionalily](https://uppy.io/docs/url/). Default: `false`. #### `enableGooglePickerEndpoint` `COMPANION_ENABLE_GOOGLE_PICKER_ENDPOINT` Set this to `true` to enable the Google Picker (Photos / Drive) functionality. Default: `false`. #### `uploadHeaders` `COMPANION_UPLOAD_HEADERS` An object with key-value pairs of static headers that will be passed along from Companion to the upload _destination_. Can be used for authenticating requests. For the environment variable, use a JSON-encoded string. Default: `{}`. ### Events The object returned by `companion.app()` also has a property `companionEmitter` which is an `EventEmitter` that emits the following events: - `upload-start` - When an upload starts, this event is emitted with an object containing the property `token`, which is a unique ID for the upload. - **token** - The event name is the token from `upload-start`. The event has an object with the following properties: - `action` - One of the following strings: - `success` - When the upload succeeds. - `error` - When the upload fails with an error. - `payload` - the error or success payload. Example code for using the `EventEmitter` to handle a finished file upload: ```js const companionApp = companion.app(options); const { companionEmitter: emitter } = companionApp; emitter.on('upload-start', ({ token }) => { console.log('Upload started', token); function onUploadEvent({ action, payload }) { if (action === 'success') { emitter.off(token, onUploadEvent); // avoid listener leak console.log('Upload finished', token, payload.url); } else if (action === 'error') { emitter.off(token, onUploadEvent); // avoid listener leak console.error('Upload failed', payload); } } emitter.on(token, onUploadEvent); }); ``` ## Frequently asked questions ### Do you have a live example? An example server is running at . ### How does the Authentication and Token mechanism work? This section describes how Authentication works between Companion and Providers. While this behaviour is the same for all Providers (Dropbox, Google Drive, etc.), we are going to be referring to Dropbox in place of any Provider throughout this section. The following steps describe the actions that take place when a user Authenticates and Uploads from Dropbox through Companion: - The visitor to a website with Uppy clicks `Connect to Dropbox`. - Uppy sends a request to Companion, which in turn sends an OAuth request to Dropbox (Requires that OAuth credentials from Dropbox have been added to Companion). - Dropbox asks the visitor to log in, and whether the Website should be allowed to access your files - If the visitor agrees, Companion will receive a token from Dropbox, with which we can temporarily download files. - Companion encrypts the token with a secret key and sends the encrypted token to Uppy (client) - Every time the visitor clicks on a folder in Uppy, it asks Companion for the new list of files, with this question, the token (still encrypted by Companion) is sent along. - Companion decrypts the token, requests the list of files from Dropbox and sends it to Uppy. - When a file is selected for upload, Companion receives the token again according to this procedure, decrypts it again, and thereby downloads the file from Dropbox. - As the bytes arrive, Companion uploads the bytes to the final destination (depending on the configuration: Apache, a Tus server, S3 bucket, etc). - Companion reports progress to Uppy, as if it were a local upload. - Completed! As of Companion 7, the encrypted token is sent to the client over the WebSocket connection, so the [WebSocket server](#express-middleware-mode) has to be running for an OAuth flow to complete. Uppy clients older than 6.0 don’t ask for a token over the WebSocket, and Companion falls back to sending it with `window.opener.postMessage` from the OAuth callback page. An Uppy 6 client needs Companion 7, so upgrade Companion first. ### How to use provider redirect URIs? When generating your provider API keys on their corresponding developer platforms (e.g [Google Developer Console](https://console.developers.google.com/)), you’d need to provide a `redirect URI` for the OAuth authorization process. In general the redirect URI for each provider takes the format: `http(s)://$YOUR_COMPANION_HOST_NAME/$PROVIDER_NAME/redirect` For example, if your Companion server is hosted on `https://my.companion.server.com`, then the redirect URI you would supply for your OneDrive provider would be: `https://my.companion.server.com/onedrive/redirect` Please see [Supported Providers](https://uppy.io/docs/companion/#Supported-providers) for a list of all Providers and their corresponding names. ### How to use Companion with Kubernetes? We have a detailed [guide](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/companion/KUBERNETES.md) on running Companion in Kubernetes. ### How to add custom providers? As of now, Companion supports the [providers listed here](https://uppy.io/docs/companion/#Supported-providers) out of the box, but you may also choose to add your own custom providers. You can do this by passing the `customProviders` option when calling the Uppy `app` method. The custom provider is expected to support Oauth 1 or 2 for authentication/authorization. ```javascript import providerModule from './path/to/provider/module'; const options = { customProviders: { myprovidername: { config: { authorize_url: 'https://mywebsite.com/authorize', access_url: 'https://mywebsite.com/token', oauth: 2, key: '***', secret: '***', scope: ['read', 'write'], }, module: providerModule, }, }, }; uppy.app(options); ``` The `customProviders` option should be an object containing each custom provider. Each custom provider would, in turn, be an object with two keys, `config` and `module`. The `config` option would contain Oauth API settings, while the `module` would point to the provider module. To work well with Companion, the **module** must be a class with the following methods. Note that the methods must be `async`, return a `Promise` or reject with an `Error`): 1. `async list ({ token, directory, query })` - Returns a object containing a list of user files (such as a list of all the files in a particular directory). See [example returned list data structure](#list-data). `token` - authorization token (retrieved from oauth process) to send along with your request - `directory` - the id/name of the directory from which data is to be retrieved. This may be ignored if it doesn’t apply to your provider - `query` - expressjs query params object received by the server (in case some data you need in there). 2. `async download ({ token, id, query })` - Downloads a particular file from the provider. Returns an object with a single property `{ stream }` - a [`stream.Readable`](https://nodejs.org/api/stream.html#stream_class_stream_readable), which will be read from and uploaded to the destination. To prevent memory leaks, make sure you release your stream if you reject this method with an error. - `token` - authorization token (retrieved from oauth process) to send along with your request. - `id` - ID of the file being downloaded. - `query` - expressjs query params object received by the server (in case some data you need in there). 3. `async size ({ token, id, query })` - Returns the byte size of the file that needs to be downloaded as a `Number`. If the size of the object is not known, `null` may be returned. - `token` - authorization token (retrieved from oauth process) to send along with your request. - `id` - ID of the file being downloaded. - `query` - expressjs query params object received by the server (in case some data you need in there). The class must also have: - A unique `static authProvider` string property - a lowercased value which indicates name of the [`grant`](https://github.com/simov/grant) OAuth2 provider to use (e.g `google` for Google). If your provider doesn’t use OAuth2, you can omit this property. - A `static` property `static version = 2`, which is the current version of the Companion Provider API. See also [example code with a custom provider](https://github.com/transloadit/uppy/blob/main/examples/custom-provider/server). #### list data ```json { // username or email of the user whose provider account is being accessed "username": "johndoe", // list of files and folders in the directory. An item is considered a folder // if it mainly exists as a collection to contain sub-items "items": [ { // boolean value of whether or NOT it's a folder "isFolder": false, // icon image URL "icon": "https://random-api.url.com/fileicon.jpg", // name of the item "name": "myfile.jpg", // the mime type of the item. Only relevant if the item is NOT a folder "mimeType": "image/jpg", // the id (in string) of the item "id": "uniqueitemid", // thumbnail image URL. Only relevant if the item is NOT a folder "thumbnail": "https://random-api.url.com/filethumbnail.jpg", // for folders this is typically the value that will be passed as "directory" in the list(...) method. // For files, this is the value that will be passed as id in the download(...) method. "requestPath": "file-or-folder-requestpath", // datetime string (in ISO 8601 format) of when this item was last modified "modifiedDate": "2020-06-29T19:59:58Z", // the size in bytes of the item. Only relevant if the item is NOT a folder "size": 278940, "custom": { // an object that may contain some more custom fields that you may need to send to the client. Only add this object if you have a need for it. "customData1": "the value", "customData2": "the value" } // more items here } ], // if the "items" list is paginated, this is the request path needed to fetch the next page. "nextPagePath": "directory-name?cursor=cursor-to-next-page" } ``` ### How to run Companion locally? 1. To set up Companion for local development, please clone the Uppy repo and install, like so: ```bash git clone https://github.com/transloadit/uppy cd uppy yarn install ``` 2. Configure your environment variables by copying the `env.example.sh` file to `env.sh` and edit it to its correct values. ```bash cp .env.example .env $EDITOR .env ``` 3. To start the server, run: ```bash yarn run start:companion ``` This would get the Companion instance running on `http://localhost:3020`. It uses [`node --watch`](https://nodejs.org/api/cli.html#--watch) so it will automatically restart when files are changed. [box]: /docs/box [dropbox]: /docs/dropbox [facebook]: /docs/facebook [googledrive]: /docs/google-drive [googledrivepicker]: /docs/google-drive-picker [googlephotospicker]: /docs/google-photos-picker [onedrive]: /docs/onedrive [unsplash]: /docs/unsplash [url]: /docs/url [zoom]: /docs/zoom [transloadit]: https://transloadit.com [template-credentials]: https://transloadit.com/docs/topics/template-credentials/ --- Source: https://uppy.io/docs/comparison # Comparison of uploaders Below is a comparison of **features** in Uppy versus other popular uploading software and services. | Feature | [Uppy](https://github.com/transloadit/uppy) | [Dropzone](https://www.dropzone.dev/) | [Filepond](https://pqina.nl/filepond/) | [Uploadcare](https://uploadcare.com/) | [Filestack](https://www.filestack.com/) | [Uploader.win](https://www.uploader.win/) | [UploadThing](https://uploadthing.com/) | | -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------- | | Open source (free option) | [✅](https://github.com/transloadit/uppy/) | [✅](https://github.com/dropzone/dropzone) | [✅](https://github.com/pqina/filepond) | x | x | x | x | | Managed service (paid option) | [✅](https://transloadit.com/) | [x](https://www.dropzone.dev/plus/) | x | ✅ | ✅ | ✅ | ✅ | | Resumable uploads | [✅](/docs/tus/) | ? | ? | ? | ? | ✅ | ✅ | | Edit images | [✅](/docs/image-editor/) | ? | [☑️](https://pqina.nl/pintura/?ref=uppy) ¹ | ✅ | ✅ | ✅ | ? | | Compress images | [✅](/docs/compressor/) | ? | [✅](https://pqina.nl/filepond/docs/api/plugins/image-transform/?ref=uppy) | ? | ? | ? | ? | | Advanced [file picker UX](https://uppy.io/blog/uppy-4.0/#ux-improvements-for-viewing-remote-files) | ✅ | x | x | x ² | ✅ | ⚠️ Broken 2025-08 | x | | i18n | ✅ | ✅ | [✅](https://github.com/pqina/filepond/issues/39) | [✅](https://uploadcare.com/docs/file-uploader/localization/) | [✅](https://filestack.github.io/filestack-js/interfaces/PickerOptions.html#lang) | ⚠️ Broken 2025-08 | x | | Themes | [Limited](/docs/dashboard/#theme) | ✅ | ? | ✅ | ✅ | ? | ✅ | | Headless components | [✅](/docs/react/#headless-components) | [✅](https://react-dropzone.js.org/) | x | x | x | x | [✅](https://docs.uploadthing.com/api-reference/react) | | Hooks (fully customisable components) | [✅](/docs/react/#hooks) | [✅](https://react-dropzone.js.org/) | x | x | x | x | [✅](https://docs.uploadthing.com/api-reference/react) | | Server-side integration | [✅](/docs/companion/) | [x](https://docs.dropzone.dev/getting-started/setup/server-side-implementation) | [x](https://pqina.nl/filepond/docs/api/server/) | [✅](https://uploadcare.com/docs/uploads/storage/) | [✅](https://www.filestack.com/docs/uploads/storage/) | ⚠️ Broken 2025-08 | [✅](https://docs.uploadthing.com/api-reference/server) | | Server-side restrictions and access control | [Limited](https://github.com/transloadit/uppy/issues/3527) | ? | ? | ? | ? | ? | ? | | Client-side restrictions | ✅ | ? | ? | ? | ? | ? | ? | ¹ Non-free feature addon to free software.\ ² No multi-file select inside folder (with checkbox). ## Framework support We consider uploades that provide supported wrappers for each framework. | Framework | [Uppy](https://github.com/transloadit/uppy) | [Dropzone](https://www.dropzone.dev/) | [Filepond](https://pqina.nl/filepond/) | [Uploadcare](https://uploadcare.com/) | [Filestack](https://www.filestack.com/) | [Uploader.win](https://www.uploader.win/) | [UploadThing](https://uploadthing.com/) | | --------- | ------------------------------------------- | ------------------------------------- | -------------------------------------- | -------------------------------------------------------- | --------------------------------------- | ----------------------------------------- | --------------------------------------- | | Angular | ✅ | x | ✅ | ✅ | ✅ | ? | x | | React | ✅ | x | ✅ | ✅ | ✅ | ? | ✅ | | Next.js | ✅ | x | ✅ | ✅ | x | ? | ✅ | | Svelte | ✅ | x | ✅ | ✅ | x | ? | ✅ | | Vue | ✅ | x | ✅ | ✅ | x | ? | ✅ | | jQuery | x | x | ✅ | [✅](https://uploadcare.com/docs/uploads/file-uploader/) | x | ? | x | ## Sources Upload sources are where the uploaded file originates from. | | [Uppy](https://github.com/transloadit/uppy) | [Dropzone](https://www.dropzone.dev/) | [Filepond](https://pqina.nl/filepond/) | [Uploadcare](https://uploadcare.com/) | [Filestack](https://www.filestack.com/) | [Uploader.win](https://www.uploader.win/) | [UploadThing](https://uploadthing.com/) | | ---------------------- | ------------------------------------------- | ------------------------------------- | -------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------------- | --------------------------------------- | | Google Drive | [✅ ¹](/docs/google-drive/) | x | x | ✅ | ✅ | ⚠️ Broken 2025-03 | x | | Google Drive Picker | [✅](/docs/google-drive-picker/) | x | x | x | x | x | x | | Google Photos ² | x | x | x | x | x | x | x | | Google Photos Picker | [✅](/docs/google-photos-picker/) | x | x | x | x | x | x | | Dropbox Personal | [✅](/docs/dropbox/) | x | x | ✅ | ✅ | ⚠️ Broken 2025-03 | x | | Dropbox Business Teams | [✅](/docs/dropbox/) | x | x | x | x | x | x | | Box | [✅](/docs/box/) | x | x | ✅ | ✅ | x | x | | OneDrive | [✅](/docs/onedrive/) | x | x | ✅ | ✅ | x | x | | Zoom | [✅](/docs/zoom/) | x | x | x | x | x | x | | WebDAV | [✅](/docs/webdav/) | x | x | x | x | x | x | | Facebook | [✅](/docs/facebook/) | x | x | ✅ | ✅ | ⚠️ Broken 2025-03 | x | | Instagram ³ | x (removed in 6.0) | x | x | x | [⚠️ Disabled 2025-01](https://developers.facebook.com/blog/post/2024/09/04/update-on-instagram-basic-display-api/) | x | x | | Link (URL) | [✅](/docs/url/) | x | x | ✅ | ✅ | ✅ | x | | Image search | [✅](/docs/unsplash/) | x | x | x | ✅ | ✅ | x | | Webcam | [✅](/docs/webcam/) | x | x | ✅ | ✅ | ✅ | x | | Microphone | [✅](/docs/audio/) | x | x | x | ✅ | ✅ | x | | Screen capture | [✅](/docs/screen-capture/) | x | x | x | x | x | x | ¹ Requires your own credentials and Google validation.\ ² API has been disabled by Google.\ ³ Only Business API (personal API removed by Instagram).\ ## Uploaders We only consider those destinations that the uploader can upload to directly (without first uploading to a managed service). | Destination | [Uppy](https://github.com/transloadit/uppy) | [Dropzone](https://www.dropzone.dev/) | [Filepond](https://pqina.nl/filepond/) | [Uploadcare](https://uploadcare.com/) | [Filestack](https://www.filestack.com/) | [Uploader.win](https://www.uploader.win/) | [UploadThing](https://uploadthing.com/) | | ---------------------- | ------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------- | ------------------------------------- | --------------------------------------- | ----------------------------------------- | --------------------------------------- | | Custom HTTP backend | [✅](/docs/xhr-upload/) | [✅](https://docs.dropzone.dev/getting-started/setup/server-side-implementation) | [✅](https://pqina.nl/filepond/docs/api/server/) | x | x | ⚠️ Broken 2025-03 | x | | AWS S3 | [✅](/docs/aws-s3/) | x | [✅](https://github.com/pqina/filepond/issues/55) | x | x | ⚠️ Broken 2025-03 | x | | AWS S3 multipart | [✅](/docs/aws-s3/) | x | [✅](https://github.com/pqina/filepond/issues/55) | x | x | ⚠️ Broken 2025-03 | x | | [Tus](https://tus.io/) | [✅](/docs/tus/) | x | [✅](https://github.com/pqina/filepond/issues/48) | x | x | ⚠️ Broken 2025-03 | x | --- Source: https://uppy.io/docs/compressor # Compressor The `@uppy/compressor` plugin optimizes images (JPEG, PNG, and any other format supported by the client’s browser) before upload, saving up to 60% in size (roughly 18 MB for 10 images). It uses [Compressor.js][] library under the hood. ## When should I use it? When your users are likely to upload images, potentially on mobile devices, and saving data and faster uploads are important. ## Install **NPM** ```shell npm install @uppy/compressor ``` **Yarn** ```shell yarn add @uppy/compressor ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js {7} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import Compressor from '@uppy/compressor'; new Uppy() .use(Dashboard, {inline:true, target: '#dashboard') .use(Compressor); ``` No action is needed from the user — Uppy will automatically optimize images, show an [Informer](/docs/informer) message with saved bytes, and then begin the upload as usual. ## API ### Options :::tip You can also pass any of the [Compressor.js options][] here as well. ::: #### `id` A unique identifier for this plugin (`string`, default: `'Compressor'`). #### `quality` The quality of the output image passed to [Compressor.js][] (`number`, default: `0.6`). It must be a number between `0` and `1`. Be careful to use `1` as it may make the size of the output image become larger. In most cases, going with the default value is best. :::note This option is only available for `image/jpeg` and `image/webp` images. ::: #### `limit` Number of images that will be compressed in parallel (`number`, default: `10`). You likely don’t need to change this, unless you are experiencing performance issues. #### `locale` ```js export default { strings: { // Shown in the Status Bar compressingImages: 'Compressing images...', compressedX: 'Saved %{size} by compressing images', }, }; ``` ### Events #### `compressor:complete` The event is emitted when all files are compressed. You can use it for side effects or custom UI notifications. [compressor.js]: https://github.com/fengyuanchen/compressorjs [compressor.js options]: https://github.com/fengyuanchen/compressorjs#options --- Source: https://uppy.io/docs/guides/custom-stores # Custom stores If your app uses a state management library such as [Redux](https://redux.js.org), it can be useful to have Uppy store its state there instead. That way, you could write custom uploader UI components in the same way as the other components in the application. Uppy comes with one built-in state management solution (store): - `@uppy/core/store-default`, a basic object-based store. You can also use a third-party store: - [uppy-store-ngrx](https://github.com/rimlin/uppy-store-ngrx/), keeping Uppy state in a key in an [Ngrx](https://github.com/ngrx/platform) store for use with Angular. ## Using stores To use a store, pass an instance to the [`store` option](/docs/uppy/#store) in the Uppy constructor: ```js import DefaultStore from '@uppy/core/store-default'; const uppy = new Uppy({ store: new DefaultStore(), }); ``` ### `DefaultStore` Uppy uses the `DefaultStore` by default! You do not need to do anything to use it. It does not take any options. ## Implementing Stores An Uppy store is an object with three methods. - `getState()` - Return the current state object. - `setState(patch)` - Merge the object `patch` into the current state. - `subscribe(listener)` - Call `listener` whenever the state changes. `listener` is a function that should receive three parameters: `(prevState, nextState, patch)` The `subscribe()` method should return a function that “unsubscribes” (removes) the `listener`. The default store implementation, for example, looks a bit like this: ```js function createDefaultStore() { let state = {}; const listeners = new Set(); return { getState: () => state, setState: (patch) => { const prevState = state; const nextState = { ...prevState, ...patch }; state = nextState; listeners.forEach((listener) => { listener(prevState, nextState, patch); }); }, subscribe: (listener) => { listeners.add(listener); return () => listeners.delete(listener); }, }; } ``` A pattern like this, where users can pass options via a function call if necessary, is recommended. See the [@uppy/core/store-default](https://github.com/transloadit/uppy/tree/main/packages/%40uppy/core/src/store) source for more inspiration. --- Source: https://uppy.io/docs/dashboard # Dashboard The all you need Dashboard: powerful, responsive, and pluggable. Kickstart your uploading experience and gradually add more functionality. Add files from [remote sources](/docs/companion), [edit images](/docs/image-editor), [generate thumbnails](/docs/thumbnail-generator), and more. Checkout [integrations](#integrations) for the full list of plugins you can integrate. :::tip [Try out the live example with all plugins](/examples) or take it for a spin in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-zaqyaf?file=main.js). ::: ## When should I use this? There could be many reasons why you may want to use the Dashboard, but some could be: - when you need a battle tested plug-and-play uploading UI to save time. - when your users need to add files from [remote sources](/docs/companion), such [Google Drive](/docs/google-drive), [Dropbox](/docs/dropbox), and others. - when you need to collect [meta data](#metafields) from your users per file. - when your users want to take a picture with their [webcam](/docs/webcam) or [capture their screen](/docs/screen-capture). ## Install **NPM** ```shell npm install @uppy/core @uppy/dashboard ``` **Yarn** ```shell yarn add @uppy/core @uppy/dashboard ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy().use(Dashboard, { inline: true, target: '#uppy-dashboard' }); ``` :::note The `@uppy/dashboard` plugin includes CSS for the Dashboard itself, and the various plugins used by the Dashboard, such as ([`@uppy/status-bar`](/docs/status-bar) and [`@uppy/informer`](/docs/informer)). If you also use the `@uppy/status-bar` or `@uppy/informer` plugin directly, you should not include their CSS files, but instead only use the one from the `@uppy/dashboard` plugin. ::: :::note Styles for Provider plugins, like Google Drive and Dropbox, are also bundled with Dashboard styles. Styles for other plugins, such as `@uppy/url` and `@uppy/webcam`, are not included. If you are using those, please see their docs and make sure to include styles for them as well. ::: ## Restrictions Dashboard follows the core [`restrictions`](/docs/uppy/#restrictions) option (file size, type filters, counts, etc.). Configure restrictions on your Uppy instance and they will automatically apply to the Dashboard UI. ## API ### Options #### `id` A unique identifier for this plugin (`string`, default: `'Dashboard'`). Plugins that are added by the Dashboard get unique IDs based on this ID, like `'Dashboard:StatusBar'` and `'Dashboard:Informer'`. #### `target` Where to render the Dashboard (`string` or `Element`, default: `'body'`). You can pass an element, class, or id as a string. Dashboard is rendered into `body`, because it’s hidden by default and only opened as a modal when `trigger` is clicked. #### `inline` Render the Dashboard as a modal or inline (`boolean`, default: `false`). When `false`, Dashboard is opened by clicking on [`trigger`](#trigger). If `inline: true`, Dashboard will be rendered into [`target`](#target) and fit right in. #### `trigger` A CSS selector for a button that will trigger opening the Dashboard modal (`string`, default: `null`). Several buttons or links can be used, as long as they are selected using the same selector (`.select-file-button`, for example). #### `width` Width of the Dashboard in pixels (`number`, default: `750`). Used when `inline: true`. #### `height` Height of the Dashboard in pixels (`number`, default: `550`). Used when `inline: true`. #### `waitForThumbnailsBeforeUpload` Whether to wait for all thumbnails from `@uppy/thumbnail-generator` to be ready before starting the upload (`boolean`, default `false`). If set to `true`, Thumbnail Generator will envoke Uppy’s internal processing stage, displaying “Generating thumbnails...” message, and wait for `thumbnail:all-generated` event, before proceeding to the uploading stage. This is useful because Thumbnail Generator also adds EXIF data to images, and if we wait until it’s done processing, this data will be available on the server after the upload. #### `showLinkToFileUploadResult` Turn the file icon and thumbnail in the Dashboard into a link to the uploaded file (`boolean`, default: `false`). Please make sure to return the `url` key (or the one set via `responseUrlFieldName`) from your server. #### `showProgressDetails` Show or hide progress details in the status bar (`boolean`, default: `false`). By default, progress in Status Bar is shown as a percentage. If you would like to also display remaining upload size and time, set this to `true`. `showProgressDetails: false`: Uploading: 45% `showProgressDetails: true`: Uploading: 45%・43 MB of 101 MB・8s left #### `hideUploadButton` Show or hide the upload button (`boolean`, default: `false`). Use this if you are providing a custom upload button somewhere, and are using the `uppy.upload()` API. #### `hideRetryButton` Hide the retry button in the status bar and on each individual file (`boolean`, default: `false`). Use this if you are providing a custom retry button somewhere and if you are using the `uppy.retryAll()` or `uppy.retryUpload(fileID)` API. #### `hidePauseResumeButton` Hide the pause/resume button (for resumable uploads, via [tus](http://tus.io), for example) in the status bar and on each individual file (`boolean`, default: `false`). Use this if you are providing custom cancel or pause/resume buttons somewhere, and using the `uppy.pauseResume(fileID)` or `uppy.removeFile(fileID)` API. #### `hideCancelButton` Hide the cancel button in status bar and on each individual file (`boolean`, default: `false`). Use this if you are providing a custom retry button somewhere, and using the `uppy.cancelAll()` API. #### `hideProgressAfterFinish` Hide the status bar after the upload has finished (`boolean`, default: `false`). #### `doneButtonHandler` This option is passed to the status bar and will render a “Done” button in place of pause/resume/cancel buttons, once the upload/encoding is done. The behaviour of this “Done” button is defined by this handler function, for instance to close the file picker modals or clear the upload state. This is what the Dashboard sets by default: ```js const doneButtonHandler = () => { this.uppy.cancelAll(); this.requestCloseModal(); }; ``` Set to `null` to disable the “Done” button. #### `showSelectedFiles` Show the list of added files with a preview and file information (`boolean`, default: `true`). In case you are showing selected files in your own app’s UI and want the Uppy Dashboard to only be a picker, the list can be hidden with this option. See also [`disableStatusBar`](#disablestatusbar) option, which can hide the progress and upload button. #### `showRemoveButtonAfterComplete` Show the remove button on every file after a successful upload (`boolean`, default: `false`). Enabling this option only shows the remove `X` button in the Dashboard UI, but to actually send a request you should listen to [`file-removed`](https://uppy.io/docs/uppy/#file-removed) event and add your logic there. Example: ```js uppy.on('file-removed', (file, reason) => { if (reason === 'removed-by-user') { sendDeleteRequestForFile(file); } }); ``` For an implementation example, please see [#2301](https://github.com/transloadit/uppy/issues/2301#issue-628931176). #### `singleFileFullScreen` When only one file is selected, its preview and meta information will be centered and enlarged (`boolean`, default: `true`). Often times Uppy used for photo / profile image uploads, or maybe a single document. Then it makes sense to occupy the whole space of the available Dashboard UI, giving the stage to this one file. This feature is automatically disabled when Dashboard is small in height, since there’s not enough room. #### `note` A string of text to be placed in the Dashboard UI (`string`, default: `null`). This could for instance be used to explain any [`restrictions`](#restrictions) that are put in place. For example: `'Images and video only, 2-3 files, up to 1 MB'`. #### `metaFields` Create text or custom input fields for the user to fill in (`Array` or `Function`, default: `null`). This will be shown when a user clicks the “edit” button on that file. :::note The meta data will only be set on a file object if it’s entered by the user. If the user doesn’t edit a file’s metadata, it will not have default values; instead everything will be `undefined`. If you want to set a certain meta field to each file regardless of user actions, set [`meta` in the Uppy constructor options](/docs/uppy/#meta). ::: Each object can contain: - `id`. The name of the meta field. This will also be used in CSS/HTML as part of the `id` attribute, so it’s better to [avoid using characters like periods, semicolons, etc](https://stackoverflow.com/a/79022). - `name`. The label shown in the interface. - `placeholder`. The text shown when no value is set in the field. (Not needed when a custom render function is provided) - `render: ({value, onChange, required, form}, h) => void` (optional). A function for rendering a custom form element. - `value` is the current value of the meta field - `onChange: (newVal) => void` is a function saving the new value and `h` is the `createElement` function from [Preact](https://preactjs.com/guide/v10/api-reference#h--createelement). - `required` is a boolean that’s true if the field `id` is in the `restrictedMetaFields` restriction - `form` is the `id` of the associated `
` element. - `h` can be useful when using Uppy from plain JavaScript, where you cannot write JSX.
Example: meta fields configured as an `Array` ```js uppy.use(Dashboard, { trigger: '#pick-files', metaFields: [ { id: 'name', name: 'Name', placeholder: 'file name' }, { id: 'license', name: 'License', placeholder: 'specify license' }, { id: 'caption', name: 'Caption', placeholder: 'describe what the image is about', }, { id: 'public', name: 'Public', render({ value, onChange, required, form }, h) { return h('input', { type: 'checkbox', required, form, onChange: (ev) => onChange(ev.target.checked ? 'on' : ''), defaultChecked: value === 'on', }); }, }, ], }); ```
Example: dynamic meta fields based on file type with a `Function` ```js uppy.use(Dashboard, { trigger: '#pick-files', metaFields: (file) => { const fields = [{ id: 'name', name: 'File name' }]; if (file.type.startsWith('image/')) { fields.push({ id: 'location', name: 'Photo Location' }); fields.push({ id: 'alt', name: 'Alt text' }); fields.push({ id: 'public', name: 'Public', render: ({ value, onChange, required, form }, h) => { return h('input', { type: 'checkbox', onChange: (ev) => onChange(ev.target.checked ? 'on' : ''), defaultChecked: value === 'on', required, form, }); }, }); } return fields; }, }); ```
#### `closeModalOnClickOutside` Set to true to automatically close the modal when the user clicks outside of it (`boolean`, default: `false`). #### `closeAfterFinish` Set to true to automatically close the modal when all current uploads are complete (`boolean`, default: `false`). With this option, the modal is only automatically closed when uploads are complete _and successful_. If some uploads failed, the modal stays open so the user can retry failed uploads or cancel the current batch and upload an entirely different set of files instead. :::info You can use this together with the [`allowMultipleUploadBatches: false`](/docs/uppy/#allowmultipleuploadbatches) option in Uppy Core to create a smooth experience when uploading a single (batch of) file(s). This is recommended. With several upload batches, the auto-closing behavior can be quite confusing for users. ::: #### `disablePageScrollWhenModalOpen` Disable page scroll when the modal is open (`boolean`, default: `true`). Page scrolling is disabled by default when the Dashboard modal is open, so when you scroll a list of files in Uppy, the website in the background stays still. Set to false to override this behaviour and leave page scrolling intact. #### `animateOpenClose` Add animations when the modal dialog is opened or closed, for a more satisfying user experience (`boolean`, default: `true`). #### `fileManagerSelectionType` Configure the type of selections allowed when browsing your file system via the file manager selection window (`string`, default: `'files'`). May be either `'files'`, `'folders'`, or `'both'`. Selecting entire folders for upload may not be supported on all [browsers](https://caniuse.com/#feat=input-file-directory). #### `proudlyDisplayPoweredByUppy` Show the Uppy logo with a link (`boolean`, default: `true`). Uppy is provided to the world for free by the team behind [Transloadit](https://transloadit.com). In return, we ask that you consider keeping a tiny Uppy logo at the bottom of the Dashboard, so that more people can discover and use Uppy. #### `disableStatusBar` Disable the status bar completely (`boolean`, default: `false`). Dashboard ships with the `StatusBar` plugin that shows upload progress and pause/resume/cancel buttons. If you want, you can disable the StatusBar to provide your own custom solution. #### `disableInformer` Disable informer (shows notifications in the form of toasts) completely (`boolean`, default: `false`). Dashboard ships with the `Informer` plugin that notifies when the browser is offline, or when it’s time to say cheese if `Webcam` is taking a picture. If you want, you can disable the Informer and/or provide your own custom solution. #### `disableThumbnailGenerator` Disable the thumbnail generator completely (`boolean`, default: `false`). Dashboard ships with the `ThumbnailGenerator` plugin that adds small resized image thumbnails to images, for preview purposes only. If you want, you can disable the `ThumbnailGenerator` and/or provide your own custom solution. #### `locale` ```js module.exports = { strings: { // When `inline: false`, used as the screen reader label for the button that closes the modal. closeModal: 'Close Modal', // Used as the screen reader label for the plus (+) button that shows the “Add more files” screen addMoreFiles: 'Add more files', addingMoreFiles: 'Adding more files', // Used as the header for import panels, e.g., “Import from Google Drive”. importFrom: 'Import from %{name}', // When `inline: false`, used as the screen reader label for the dashboard modal. dashboardWindowTitle: 'Uppy Dashboard Window (Press escape to close)', // When `inline: true`, used as the screen reader label for the dashboard area. dashboardTitle: 'Uppy Dashboard', // Shown in the Informer when a link to a file was copied to the clipboard. copyLinkToClipboardSuccess: 'Link copied to clipboard.', // Used when a link cannot be copied automatically. The user has to select the text from the // input element below this string. copyLinkToClipboardFallback: 'Copy the URL below', // Used as the hover title and screen reader label for buttons that copy a file link. copyLink: 'Copy link', back: 'Back', // Used as the screen reader label for buttons that remove a file. removeFile: 'Remove file', // Used as the screen reader label for buttons that open the metadata editor panel for a file. editFile: 'Edit file', // Shown in the panel header for the metadata editor. Rendered as “Editing image.png”. editing: 'Editing %{file}', // Used as the screen reader label for the button that saves metadata edits and returns to the // file list view. finishEditingFile: 'Finish editing file', saveChanges: 'Save changes', // Used as the label for the tab button that opens the system file selection dialog. myDevice: 'My Device', dropHint: 'Drop your files here', // Used as the hover text and screen reader label for file progress indicators when // they have been fully uploaded. uploadComplete: 'Upload complete', uploadPaused: 'Upload paused', // Used as the hover text and screen reader label for the buttons to resume paused uploads. resumeUpload: 'Resume upload', // Used as the hover text and screen reader label for the buttons to pause uploads. pauseUpload: 'Pause upload', // Used as the hover text and screen reader label for the buttons to retry failed uploads. retryUpload: 'Retry upload', // Used as the hover text and screen reader label for the buttons to cancel uploads. cancelUpload: 'Cancel upload', // Used in a title, how many files are currently selected xFilesSelected: { 0: '%{smart_count} file selected', 1: '%{smart_count} files selected', }, uploadingXFiles: { 0: 'Uploading %{smart_count} file', 1: 'Uploading %{smart_count} files', }, processingXFiles: { 0: 'Processing %{smart_count} file', 1: 'Processing %{smart_count} files', }, // The "powered by Uppy" link at the bottom of the Dashboard. poweredBy: 'Powered by %{uppy}', addMore: 'Add more', editFileWithFilename: 'Edit file %{file}', save: 'Save', cancel: 'Cancel', dropPasteFiles: 'Drop files here or %{browseFiles}', dropPasteFolders: 'Drop files here or %{browseFolders}', dropPasteBoth: 'Drop files here, %{browseFiles} or %{browseFolders}', dropPasteImportFiles: 'Drop files here, %{browseFiles} or import from:', dropPasteImportFolders: 'Drop files here, %{browseFolders} or import from:', dropPasteImportBoth: 'Drop files here, %{browseFiles}, %{browseFolders} or import from:', importFiles: 'Import files from:', browseFiles: 'browse files', browseFolders: 'browse folders', recoveredXFiles: { 0: 'We could not fully recover 1 file. Please re-select it and resume the upload.', 1: 'We could not fully recover %{smart_count} files. Please re-select them and resume the upload.', }, recoveredAllFiles: 'We restored all files. You can now resume the upload.', sessionRestored: 'Session restored', reSelect: 'Re-select', missingRequiredMetaFields: { 0: 'Missing required meta field: %{fields}.', 1: 'Missing required meta fields: %{fields}.', }, }, }; ``` #### `theme` Light or dark theme for the Dashboard (`string`, default: `'light'`). Uppy Dashboard supports “Dark Mode”. You can try it live on [the Dashboard example page](https://uppy.io/examples/). It supports the following values: - `light`: the default - `dark` - `auto`: will respect the user’s system settings and switch automatically #### `autoOpen` Automatically open file editor for the file user just dropped/selected. If one file is added, editor opens for that file; if 10 files are added, editor opens only for the first file. This option supports the following values: - `null` - the default - `"metaEditor"` - open the meta fields editor if [meta fields](/docs/dashboard/#metafields) are enabled. - `"imageEditor"` - open [`@uppy/image-editor`](/docs/image-editor) if the plugin is enabled. #### `disabled` Enabling this option makes the Dashboard grayed-out and non-interactive (`boolean`, default: `false`). Users won’t be able to click on buttons or drop files. Useful when you need to conditionally enable/disable file uploading or manipulation, based on a condition in your app. Can be set on init or via API: ```js const dashboard = uppy.getPlugin('Dashboard'); dashboard.setOptions({ disabled: true }); userNameInput.addEventListener('change', () => { dashboard.setOptions({ disabled: false }); }); ``` #### `disableLocalFiles` Disable local files (`boolean`, default: `false`). Enabling this option will disable drag & drop, hide the “browse” and “My Device” button, allowing only uploads from plugins, such as Webcam, Screen Capture, Google Drive, Dropbox. #### `onDragOver(event)` Callback for the [`ondragover`][ondragover] event handler. #### `onDrop(event)` Callback for the [`ondrop`][ondrop] event handler. #### `onDragLeave(event)` Callback for the [`ondragleave`][ondragleave] event handler. ### Methods :::info Dashboard also has the methods described in [`UIPlugin`](/docs/uppy#new-uipluginuppy-options) and [`BasePlugin`](/docs/uppy#new-basepluginuppy-options). ::: #### `openModal()` Shows the Dashboard modal. Use it like this: `uppy.getPlugin('Dashboard').openModal()` #### `closeModal()` Hides the Dashboard modal. Use it like this: `uppy.getPlugin('Dashboard').closeModal()` #### `isModalOpen()` Returns `true` if the Dashboard modal is open, `false` otherwise. ```js const dashboard = uppy.getPlugin('Dashboard'); if (dashboard.isModalOpen()) { dashboard.closeModal(); } ``` ### Events :::info You can use [`on`](/docs/uppy#onevent-action) and [`once`](/docs/uppy#onceevent-action) to listen to these events. ::: #### `dashboard:modal-open` Fired when the Dashboard modal is open. ```js uppy.on('dashboard:modal-open', () => { console.log('Modal is open'); }); ``` #### `dashboard:modal-closed` Fired when the Dashboard modal is closed. #### `dashboard:file-edit-start` **Parameters:** - `file`: the [File Object](https://uppy.io/docs/uppy/#File-Objects) representing the file that was opened for editing. Fired when the user clicks “edit” icon next to a file in the Dashboard. The FileCard panel is then open with file metadata available for editing. #### `dashboard:file-edit-complete` **Parameters:** - `file`: the [File Object](https://uppy.io/docs/uppy/#File-Objects) representing the file that was edited. Fired when the user finished editing the file metadata. #### `dashboard:show-panel` **Parameters:** - `id`: the active plugin ID. Fired when the user opens a UI plugin. #### `dashboard:hide-panel` **Parameters:** - `id`: the previously active plugin ID. Fired when the user closes a UI plugin. ## Integrations These are the plugins specifically made for the Dashboard. This is not a list of all Uppy plugins. ### Sources - [`@uppy/audio`](/docs/audio): record audio. - [`@uppy/box`](/docs/box): import files from [Box](https://www.box.com/en-nl/home). - [`@uppy/dropbox`](/docs/dropbox): import from [Dropbox](https://dropbox.com). - [`@uppy/facebook`](/docs/facebook): import from [Facebook](https://facebook.com). - [`@uppy/google-drive`](/docs/google-drive): import from [Google Drive](https://drive.google.com). Needs your own Google OAuth app, verified by Google for production use, also on Transloadit-hosted Companion. - [`@uppy/google-drive-picker`](/docs/google-drive-picker): import from [Google Drive](https://drive.google.com) using the new Picker API. - [`@uppy/google-photos-picker`](/docs/google-photos-picker): import from [Google Photos](https://drive.google.com) using the new Picker API. - [`@uppy/onedrive`](/docs/onedrive): import from [OneDrive](https://www.microsoft.com/en-us/microsoft-365/onedrive/online-cloud-storage). - [`@uppy/screen-capture`](/docs/screen-capture): Record your screen, including (optionally) your microphone. - [`@uppy/unsplash`](/docs/unsplash): import files from [Unsplash](https://unsplash.com/) - [`@uppy/url`](/docs/url): import files from any URL. - [`@uppy/webcam`](/docs/webcam): Record or make a picture with your webcam. - [`@uppy/zoom`](/docs/zoom): import files from [Zoom](https://zoom.us). ### UI - [`@uppy/image-editor`](/docs/image-editor): allows users to crop, rotate, zoom and flip images that are added to Uppy. - [`@uppy/informer`](/docs/informer): show notifications. - [`@uppy/status-bar`](/docs/status-bar): advanced upload progress status bar. - [`@uppy/thumbnail-generator`](/docs/thumbnail-generator): generate preview thumbnails for images to be uploaded. ### Frameworks - [`@uppy/angular`](/docs/angular): Dashboard component for [Angular](https://angular.io/). - [`@uppy/react`](/docs/react): Dashboard component for [React](https://reactjs.org/). - [`@uppy/svelte`](/docs/svelte): Dashboard component for [Svelte](https://svelte.dev/). - [`@uppy/vue`](/docs/vue): Dashboard component for [Vue](https://vuejs.org/). [ondragover]: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/ondragover [ondragleave]: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/ondragleave [ondrop]: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/ondrop --- Source: https://uppy.io/docs/drag-drop # Drag & Drop The `@uppy/drag-drop` plugin renders a drag and drop area for file selection. :::info Using React, Vue, or Svelte? The framework wrappers for this plugin were removed in Uppy 5.0. Use the `Dropzone` component or `useDropzone` hook from [`@uppy/react`](/docs/react), [`@uppy/vue`](/docs/vue), or [`@uppy/svelte`](/docs/svelte) instead. This plugin remains supported for vanilla JavaScript and no-build setups. ::: :::tip [Try out the live example](/examples) or take it for a spin in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-yzbujq?file=main.js/g). ::: ## When should I use this? It can be useful when you only want the local device as a file source, don’t need file previews and a UI for metadata editing, or the [Dashboard](/docs/dashboard/) is too much. But it can be too minimal too. By default it doesn’t show that a file has been added nor is there a progress bar. ## Install **NPM** ```shell npm install @uppy/core @uppy/drag-drop ``` **Yarn** ```shell yarn add @uppy/core @uppy/drag-drop ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js showLineNumbers import Uppy from '@uppy/core'; import DragDrop from '@uppy/drag-drop'; import '@uppy/core/css/style.min.css'; import '@uppy/drag-drop/css/style.min.css'; new Uppy().use(DragDrop, { target: '#drag-drop' }); ``` :::info Certain [restrictions](/docs/uppy#restrictions) set in Uppy’s options, namely `maxNumberOfFiles` and `allowedFileTypes`, affect the system file picker dialog. If `maxNumberOfFiles: 1`, users will only be able to select one file, and `allowedFileTypes: ['video/*', '.gif']` means only videos or gifs (files with `.gif` extension) will be selectable. ::: ## API ### Options #### `id` A unique identifier for this plugin (`string`, Default: `'DragDrop'`). Use this if you need to add several DragDrop instances. #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string` or `Element`, default: `null`). #### `width` Drag and drop area width (`string`, default: `'100%'`). Set in inline CSS, so feel free to use percentage, pixels or other values that you like. #### `height` Drag and drop area height (`string`, default: `'100%'`). Set in inline CSS, so feel free to use percentage, pixels or other values that you like. #### `note` Optionally, specify a string of text that explains something about the upload for the user (`string`, default: `null`). This is a place to explain any `restrictions` that are put in place. For example: `'Images and video only, 2–3 files, up to 1 MB'`. #### `locale` ```js export default { strings: { // Text to show on the droppable area. // `%{browse}` is replaced with a link that opens the system file selection dialog. dropHereOr: 'Drop here or %{browse}', // Used as the label for the link that opens the system file selection dialog. browse: 'browse', }, }; ``` #### `onDragOver(event)` Callback for the [`ondragover`][ondragover] event handler. #### `onDragLeave(event)` Callback for the [`ondragleave`][ondragleave] event handler. #### `onDrop(event)` Callback for the [`ondrop`][ondrop] event handler. [ondragover]: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/ondragover [ondragleave]: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/ondragleave [ondrop]: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/ondrop --- Source: https://uppy.io/docs/drop-target # Drop target The `@uppy/drop-target` plugin lets your users drag-and-drop files on any element on the page, for example the whole page, `document.body`. Can be used together with Uppy Dashboard or Drag & Drop plugins, or your custom solution targeting any DOM element. :::tip [Try out the live example](/examples) or take it for a spin in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-yzbujq?file=main.js/g). ::: ## When should I use this? When you want to allow users to drag and drop files in your own UI, rather than in the [`Dashboard`](/docs/dashboard) UI, or catch dropped files from anywhere on the page. ## Install **NPM** ```shell npm install @uppy/drop-target ``` **Yarn** ```shell yarn add @uppy/drop-target ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use This module has one default export: the `DropTarget` plugin class. ```js {8-10} showLineNumbers import Uppy from '@uppy/core'; import DropTarget from '@uppy/drop-target'; import '@uppy/core/css/style.css'; import '@uppy/drop-target/css/style.css'; const uppy = new Uppy(); uppy.use(DropTarget, { target: document.body, }); ``` ## API ### Options #### `onDragLeave` Event listener for the [`dragleave` event][]. ```js {3-5} showLineNumbers uppy.use(DropTarget, { target: document.body, onDragLeave: (event) => { event.stopPropagation(); }, }); ``` #### `onDragOver` Event listener for the [`dragover` event][]. #### `onDrop` Event listener for the [`drop` event][]. #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: `null`). [`dragover` event]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragover_event [`dragleave` event]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragleave_event [`drop` event]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/drop_event --- Source: https://uppy.io/docs/dropbox # Dropbox The `@uppy/dropbox` plugin lets users import files from their [Dropbox](https://www.dropbox.com) account. :::tip [Try out the live example](/examples) or take it for a spin in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-zaqyaf?file=main.js). ::: ## When should I use this? When you want to let users import files from their [Dropbox](https://www.dropbox.com) account. A [Companion](/docs/companion) instance is required for the Dropbox plugin to work. Companion handles authentication with Dropbox, downloads the files, and uploads them to the destination. This saves the user bandwidth, especially helpful if they are on a mobile connection. You can self-host Companion or get a hosted version with any [Transloadit plan](https://transloadit.com/pricing/). **NPM** ```shell npm install @uppy/dropbox ``` **Yarn** ```shell yarn add @uppy/dropbox ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use Using Dropbox requires setup in both Uppy and Companion. ### Use in Uppy ```js {10-13} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import Dropbox from '@uppy/dropbox'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(Dropbox, { companionUrl: 'https://your-companion.com' }); ``` ### Use with Transloadit ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Dropbox from '@uppy/dropbox'; uppy.use(Dropbox, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }); ``` You may also hit rate limits, because the OAuth application is shared between everyone using Transloadit. To solve that, you can use your own OAuth keys with Transloadit’s hosted Companion servers by using Transloadit Template Credentials. [Create a Template Credential][template-credentials] on the Transloadit site. Select “Companion OAuth” for the service, and enter the key and secret for the provider you want to use. Then you can pass the name of the new credentials to that provider: ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Dropbox from '@uppy/dropbox'; uppy.use(Dropbox, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'my_companion_dropbox_creds', }, }); ``` ### Use in Companion You can create a Dropbox App on the [Dropbox Developers site](https://www.dropbox.com/developers/apps/create). Things to note: - Choose the “Dropbox API”, not the business variant. - Typically you’ll want “Full Dropbox” access, unless you are absolutely certain that you need the other one. - Enable the scopes `account_info.read`, `files.metadata.read` and `files.content.read` under “Permissions”. If you want to support [Team folders / Teams spaces](https://developers.dropbox.com/dbx-team-files-guide), counterintuitively you must **not** enable any Team scopes. You’ll be redirected to the app page. This page lists the app key and app secret, which you should use to configure Companion as shown above. The app page has a “Redirect URIs” field. Here, add: ``` https://$YOUR_COMPANION_HOST_NAME/dropbox/redirect ``` If you are using Transloadit hosted Companion: ``` https://api2.transloadit.com/companion/dropbox/redirect ``` You can only use the integration with your own account initially. Make sure to apply for production status on the app page before you publish your app, or your users will not be able to sign in! Configure the Dropbox key and secret. With the standalone Companion server, specify environment variables: ```shell export COMPANION_DROPBOX_KEY="Dropbox API key" export COMPANION_DROPBOX_SECRET="Dropbox API secret" ``` When using the Companion Node.js API, configure these options: ```js companion.app({ providerOptions: { dropbox: { key: 'Dropbox API key', secret: 'Dropbox API secret', }, }, }); ``` ## API ### Options #### `id` A unique identifier for this plugin (`string`, default is a unique ID for each plugin). #### `title` Title / name shown in the UI, such as Dashboard tabs (`string`, default is the name of the plugin). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `companionUrl` URL to a [Companion](/docs/companion) instance (`string`, default: `null`). For Transloadit-hosted Companion use the `COMPANION_URL` constant exported by `@uppy/transloadit`, which is `https://api2.transloadit.com/companion`. Do not use a regional hostname such as `api2-eu-west-1.transloadit.com`: the OAuth flow then starts on one host and returns to another, and login fails with “Cannot find state in session”. #### `companionHeaders` Custom headers that should be sent along to [Companion](/docs/companion) on every request (`Object`, default: `{}`). #### `companionAllowedHosts` The valid and authorised URL(s) from which OAuth responses should be accepted (`string` or `RegExp` or `Array`). This option is useful when you have your [Companion](/docs/companion) running on several hosts. Otherwise, the default value should do fine, which uses the origin of `companionUrl`. This value can be a `string`, a `RegExp` pattern, or an `Array` of these. Strings are evaluated as regular expressions too and will be wrapped in a RegExp like so: ```js new RegExp(`^${value}$`); ``` **Important:** You must escape regex characters like `.`, or you might open your app up to security vulnerabilities. - Example correct strings - `'^(?:.*\\.)?example\.com$'` matches `example.com` and all of its subdomains. - `'https://example\.com'` matches `https://example.com` only. - Example vulnerability: `'https://www.example.com'` would allow an attacker with the domain `wwwxexample.com` to forge and inject a fraudulent token into Uppy. #### `companionKeysParams` Only applies to plugins that sign in through Companion (Google Drive, Dropbox, Box, OneDrive, …). The Google Drive Picker and Google Photos Picker ignore it; they authenticate directly with Google. Google Drive Picker uses its own `clientId`, `apiKey` and `appId`, while Google Photos Picker uses its own `clientId`. Use your own OAuth app with Transloadit-hosted Companion instead of Transloadit’s shared one (`Object`, default: `undefined`). It has two fields: - `key`: your Transloadit API key. - `credentialsName`: the name of a “Companion OAuth” credential you created in the Transloadit console, which holds the provider’s OAuth key and secret. ```js companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', } ``` Before the login popup opens, the plugin sends these values to Companion to obtain a pre-auth token, and Companion fetches the OAuth key and secret from Transloadit when the flow starts. The values are also sent along with every later request in a `uppy-credentials-params` header. Companion does not validate the credential name up front, so a wrong name only fails when a user tries to sign in. On Transloadit-hosted Companion this option is required for Google Drive, see [Google Drive: Use with Transloadit](/docs/google-drive#use-with-transloadit). #### `companionCookiesRule` This option correlates to the [RequestCredentials value](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials) (`string`, default: `'same-origin'`). This tells the plugin whether to send cookies to [Companion](/docs/companion). #### `locale` An object with `strings` property containing additional i18n strings. The key is the i18n key and the value is the English string. Example: ```js { strings: { someKey: 'Some English string', }, } ``` #### `storage` A custom storage to be used for the plugin’s persistent data. Type `AsyncStore`, default is `LocalStorage`. [template-credentials]: https://transloadit.com/docs/topics/template-credentials/ --- Source: https://uppy.io/docs/facebook # Facebook The `@uppy/facebook` plugin lets users import files from their [Facebook](https://www.facebook.com) account. :::tip [Try out the live example](/examples) or take it for a spin in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-zaqyaf?file=main.js). ::: ## When should I use this? When you want to let users import files from their [Facebook](https://www.facebook.com) account. A [Companion](/docs/companion) instance is required for the Facebook plugin to work. Companion handles authentication with Facebook, downloads the files, and uploads them to the destination. This saves the user bandwidth, especially helpful if they are on a mobile connection. You can self-host Companion or get a hosted version with any [Transloadit plan](https://transloadit.com/pricing/). **NPM** ```shell npm install @uppy/facebook ``` **Yarn** ```shell yarn add @uppy/facebook ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use Using Facebook requires setup in both Uppy and Companion. ### Use in Uppy ```js {10-13} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import Facebook from '@uppy/facebook'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(Facebook, { companionUrl: 'https://your-companion.com' }); ``` ### Use with Transloadit You can use your own OAuth keys with Transloadit’s hosted Companion servers by using Transloadit Template Credentials. [Create a Template Credential][template-credentials] on the Transloadit site. Select “Companion OAuth” for the service, and enter the key and secret for the provider you want to use. Then you can pass the name of the new credentials to that provider: ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Facebook from '@uppy/facebook'; uppy.use(Facebook, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'my_companion_dropbox_creds', }, }); ``` ### Use in Companion You can create a Facebook App on the [Facebook Developers site](https://developers.facebook.com/apps). The app page has a “Redirect URIs” field. Here, add: ``` https://$YOUR_COMPANION_HOST_NAME/facebook/redirect ``` If you are using Transloadit hosted Companion: ``` https://api2.transloadit.com/companion/facebook/redirect ``` You can only use the integration with your own account initially. Make sure to apply for production status on the app page before you publish your app, or your users will not be able to sign in! You need to set up OAuth in your Facebook app for Companion to be able to connect to users’ Facebook accounts. You have to enable “Advanced Access” for the `user_photos` permission. A precondition of that is “Business Verification” which involves setting up a Meta Business Account and submitting documents to prove business ownership. Configure the Facebook key and secret. With the standalone Companion server, specify environment variables: ```shell export COMPANION_FACEBOOK_KEY="Facebook API key" export COMPANION_FACEBOOK_SECRET="Facebook API secret" ``` When using the Companion Node.js API, configure these options: ```js companion.app({ providerOptions: { facebook: { key: 'Facebook API key', secret: 'Facebook API secret', }, }, }); ``` ## API ### Options #### `id` A unique identifier for this plugin (`string`, default is a unique ID for each plugin). #### `title` Title / name shown in the UI, such as Dashboard tabs (`string`, default is the name of the plugin). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `companionUrl` URL to a [Companion](/docs/companion) instance (`string`, default: `null`). For Transloadit-hosted Companion use the `COMPANION_URL` constant exported by `@uppy/transloadit`, which is `https://api2.transloadit.com/companion`. Do not use a regional hostname such as `api2-eu-west-1.transloadit.com`: the OAuth flow then starts on one host and returns to another, and login fails with “Cannot find state in session”. #### `companionHeaders` Custom headers that should be sent along to [Companion](/docs/companion) on every request (`Object`, default: `{}`). #### `companionAllowedHosts` The valid and authorised URL(s) from which OAuth responses should be accepted (`string` or `RegExp` or `Array`). This option is useful when you have your [Companion](/docs/companion) running on several hosts. Otherwise, the default value should do fine, which uses the origin of `companionUrl`. This value can be a `string`, a `RegExp` pattern, or an `Array` of these. Strings are evaluated as regular expressions too and will be wrapped in a RegExp like so: ```js new RegExp(`^${value}$`); ``` **Important:** You must escape regex characters like `.`, or you might open your app up to security vulnerabilities. - Example correct strings - `'^(?:.*\\.)?example\.com$'` matches `example.com` and all of its subdomains. - `'https://example\.com'` matches `https://example.com` only. - Example vulnerability: `'https://www.example.com'` would allow an attacker with the domain `wwwxexample.com` to forge and inject a fraudulent token into Uppy. #### `companionKeysParams` Only applies to plugins that sign in through Companion (Google Drive, Dropbox, Box, OneDrive, …). The Google Drive Picker and Google Photos Picker ignore it; they authenticate directly with Google. Google Drive Picker uses its own `clientId`, `apiKey` and `appId`, while Google Photos Picker uses its own `clientId`. Use your own OAuth app with Transloadit-hosted Companion instead of Transloadit’s shared one (`Object`, default: `undefined`). It has two fields: - `key`: your Transloadit API key. - `credentialsName`: the name of a “Companion OAuth” credential you created in the Transloadit console, which holds the provider’s OAuth key and secret. ```js companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', } ``` Before the login popup opens, the plugin sends these values to Companion to obtain a pre-auth token, and Companion fetches the OAuth key and secret from Transloadit when the flow starts. The values are also sent along with every later request in a `uppy-credentials-params` header. Companion does not validate the credential name up front, so a wrong name only fails when a user tries to sign in. On Transloadit-hosted Companion this option is required for Google Drive, see [Google Drive: Use with Transloadit](/docs/google-drive#use-with-transloadit). #### `companionCookiesRule` This option correlates to the [RequestCredentials value](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials) (`string`, default: `'same-origin'`). This tells the plugin whether to send cookies to [Companion](/docs/companion). #### `locale` An object with `strings` property containing additional i18n strings. The key is the i18n key and the value is the English string. Example: ```js { strings: { someKey: 'Some English string', }, } ``` #### `storage` A custom storage to be used for the plugin’s persistent data. Type `AsyncStore`, default is `LocalStorage`. [template-credentials]: https://transloadit.com/docs/topics/template-credentials/ --- Source: https://uppy.io/docs/file-input # File input ::::caution Removed As of Uppy 5.0, `@uppy/file-input` is removed. Prefer the headless hooks (e.g., `useFileInput`) from `@uppy/react`, `@uppy/vue`, or `@uppy/svelte`, or use [`@uppy/dashboard`](/docs/dashboard/). See the migration notes in the [migration guide](/docs/guides/migration-guides/). :::: The `@uppy/file-input` plugin is the most barebones UI for selecting files — it shows a single button that, when clicked, opens up the browser’s file selector. ## When should I use it? When you want users to select files from their local machine with a minimal UI. ## Install **NPM** ```shell npm install @uppy/file-input ``` **Yarn** ```shell yarn add @uppy/file-input ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js showLineNumbers import Uppy from '@uppy/core'; import FileInput from '@uppy/file-input'; import '@uppy/core/css/style.min.css'; import '@uppy/file-input/css/style.css'; new Uppy().use(FileInput, { target: '#uppy-file-input' }); ``` :::note The `@uppy/file-input` plugin includes some basic styles for use with the [`pretty`](#pretty) option, like shown in the [example](/examples). You can also choose not to use it and provide your own styles instead. Import general Core styles from `@uppy/core/css/style.css` first, then add the File Input styles from `@uppy/file-input/css/style.css`. A minified version is also available as `style.min.css` at the same path. The way to do import depends on your build system. ::: ## API ### Options #### `id` A unique identifier for this plugin (`string`, default: `'FileInput'`). #### `title` Configures the title / name shown in the UI, for instance, on Dashboard tabs (`string`, default: `'File Input'`). #### `target` DOM element, CSS selector, or plugin to place the audio into (`string` or `Element`, default: `null`). #### `pretty` When true, display a styled button that, when clicked, opens the file selector UI. When false, a plain old browser `` element is shown (`boolean`, default: `true`). #### `inputName` The `name` attribute for the `` element (`string`, default: `'files[]'`). #### `locale` ```js export default { strings: { // The same key is used for the same purpose by @uppy/robodog's `form()` API, but our // locale pack scripts can't access it in Robodog. If it is updated here, it should // also be updated there! chooseFiles: 'Choose files', }, }; ``` ## Custom file input If you don’t like the look/feel of the button rendered by `@uppy/file-input`, feel free to forgo the plugin and use your own custom button on a page, like so: ```html ``` Then add this JS to attach it to Uppy: ```js const uppy = new Uppy(/* ... */); const fileInput = document.querySelector('#my-file-input'); fileInput.addEventListener('change', (event) => { const files = Array.from(event.target.files); files.forEach((file) => { try { uppy.addFile({ source: 'file input', name: file.name, type: file.type, data: file, }); } catch (err) { if (err.isRestriction) { // handle restrictions console.log('Restriction error:', err); } else { // handle other errors console.error(err); } } }); }); // Clear the `` after the upload or when the file was removed // so the file can be uploaded again (see // https://github.com/transloadit/uppy/issues/2640#issuecomment-731034781). uppy.on('file-removed', () => { fileInput.value = null; }); uppy.on('complete', () => { fileInput.value = null; }); ``` --- Source: https://uppy.io/docs/form # Form The `@uppy/form` plugin integrates with an existing HTML `` element to extract input data from it, and send along with the Uppy upload. It then appends the upload result back to the form via a hidden input. ## When should I use this? When you have an existing HTML `` element and you would like to: - **Attach the form input values to the files.** This is useful if you want to associate meta data from the form (for example, name, location, id) with the uploaded file, so you can process it on the backend. `@uppy/form` extracts the input values before uploading/processing files and adds them to Uppy meta data state (`uppy.state.meta`), as well as and each file’s meta, and appends to the upload in an object with `[file input name attribute]` -> `[file input value]` key/values. - **Upload the files and put the response (such as the file URLs) into a hidden field** (``). Then you can POST and handle the form yourself. The appended result is a stringified version of a result returned from calling `uppy.upload()` or listening to `complete` event. - **Automatically start the file upload on submit or submit the form after file upload.** This is off by default. See [`submitOnSuccess`](#submitonsuccess) and [`triggerUploadOnSubmit`](#triggeruploadonsubmit) options respectively for details. :::note If you are using a UI framework or library like React, Vue or Svelte, you’ll most likely handle form data there as well, and thus won’t need this plugin. Instead, pass meta data to Uppy via [`uppy.setMeta()`](/docs/uppy#setmetadata) and listen to [`uppy.on('complete')`](/docs/uppy#complete) to get the upload results back. ::: ## Install **NPM** ```shell npm install @uppy/form ``` **Yarn** ```shell yarn add @uppy/form ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js title="app.js" import Uppy from '@uppy/core'; import Form from '@uppy/form'; import DragDrop from '@uppy/drag-drop'; import '@uppy/core/css/style.min.css'; import '@uppy/drag-drop/css/style.min.css'; new Uppy().use(Form, { target: '#my-form', }); ``` ```html title="index.html"
``` By default the code above will: 1. Extract meta data from the form `#my-form`. 2. Send it with the Uppy upload. 3. Those fields will then be added to Uppy meta data state (`uppy.state.meta`) and each file’s meta, and appended as (meta)data to the upload in an object with `[file input name attribute]` -> `[file input value]` key/values. 4. When Uppy completes upload/processing, it will add an `` with the stringified upload result object back to the form. :::note You can disable both of these features, see options below. ::: :::tip `@uppy/form` can also start Uppy upload automatically once the form is submitted, and even submit the form after the upload is complete. This is off by default. See [`triggerUploadOnSubmit`](#triggeruploadonsubmit) and [`submitOnSuccess`](#submitonsuccess) options below for details. ::: ## API ### Options #### `id` A unique identifier for this plugin (`string`, default: `'Form'`). #### `target` DOM element or CSS selector for the form element (`string` or `Element`, default: `null`). This is required for the plugin to work. #### `resultName` The `name` attribute for the `` where the result will be added (`string`, default: `uppyResult`). #### `getMetaFromForm` Configures whether to extract metadata from the form (`boolean`, default: `true`). When set to `true`, the Form plugin will extract all fields from a `
` element before upload begins. Those fields will then be added to Uppy meta data state (`uppy.state.meta`) and each file’s meta, and appended as (meta)data to the upload in an object with `[file input name attribute]` -> `[file input value]` key/values. #### `addResultToForm` Configures whether to add upload/encoding results back to the form in an `` element (`boolean`, default: `true`). #### `triggerUploadOnSubmit` Configures whether to start the upload when the form is submitted (`boolean`, default: `false`). When a user submits the form (via a submit button, the Enter key or otherwise), this option will prevent form submission, and instead upload files via Uppy. Then you could: - Set `submitOnSuccess: true` if you need the form to _actually_ be submitted once all files have been uploaded. - Listen for `uppy.on('complete')` event to do something else if the file uploads are all you need. For example, if the form is used for file metadata only. #### `submitOnSuccess` Configures whether to submit the form after Uppy finishes uploading/encoding (`boolean`, default: `false`). --- Source: https://uppy.io/docs/golden-retriever # Golden Retriever The `@uppy/golden-retriever` plugin saves selected files in your browser cache, so that if the browser crashes, or the user accidentally closes the tab, Uppy can restore everything and continue uploading as if nothing happened. You can read more about it [on our blog](https://uppy.io/blog/2017/07/golden-retriever/). The Golden Retriever uses these methods of browser data storage: - `IndexedDB` to store file metadata and Uppy state, and for small files, up to 10MiB per file by default. - `LocalStorage` for file metadata and Uppy state when `window.indexedDB` is not available. The plugin picks a store once, when it is installed; it does not move to `LocalStorage` later on. - `Service Worker` (_optional_) for _all_ files because, unlike `IndexedDB`, `Service Worker` can keep references to large files. Service Worker storage is _quite_ temporary though, and doesn’t persist across browser crashes or restarts. It works well, however, for accidental refreshes or closed tabs. Upon restore, the plugin first restores state from whichever of `IndexedDB` or `LocalStorage` it stored it in, and then checks both file storages (`IndexedDB` and `ServiceWorker`), merging the results. If restore is unsuccessful for certain files, they will be marked as “ghosts” in the Dashboard UI, and a message + button offering to re-select those files will be displayed. Checkout the [storage quotas](https://developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria#other_web_technologies) on MDN to see how much data can be stored depending on the device and browser. ## When should I use this? When you want extra insurance for the user-selected files. If you feel like users might spend some time picking files, tweaking descriptions etc, and will not appreciate having to do it over again if something crashes. Another use case might be when you think user might want to pick a few files, navigate away to do something else in your app or otherwise, and then come back to the same selection. ## Install **NPM** ```shell npm install @uppy/golden-retriever ``` **Yarn** ```shell yarn add @uppy/golden-retriever ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js {7} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import GoldenRetriever from '@uppy/golden-retriever'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(GoldenRetriever); ``` By default, Golden Retriever stores metadata, state, and local files up to 10 MiB in IndexedDB. If IndexedDB is unavailable, metadata and state fall back to LocalStorage, but local files require the optional Service Worker storage to be restorable. ### Enabling Service Worker With the Service Worker storage, Golden Retriever will be able to temporary store references to large files. 1. Bundle your own service worker `sw.js` file with Uppy GoldenRetriever’s service worker. :::tip For Webpack, check out [serviceworker-webpack-plugin](https://github.com/oliviertassinari/serviceworker-webpack-plugin). For vite, you can add this to your `vite.config.ts`: ```ts build: { rollupOptions: { input: { main: './index.html', sw: './sw.js', }, output: { entryFileNames: (chunk) => { if (chunk.name === 'sw') return 'sw.js' // force predictable filename return 'assets/[name].[hash].js' }, }, }, }, ``` ::: ```js title="sw.js" import '@uppy/golden-retriever/lib/ServiceWorker.js'; ``` 2. Register it in your app’s entry point: ```js // you app.js entry point uppy.use(GoldenRetriever, { serviceWorker: true }); if ('serviceWorker' in navigator) { navigator.serviceWorker .register('/sw.js', { type: 'module' }) // path to your bundled service worker which imports GoldenRetriever service worker .then((registration) => { console.log( 'ServiceWorker registration successful with scope: ', registration.scope, ); }) .catch((error) => { console.log(`Registration failed with ${error}`); }); } ``` Voilà, that’s it. Happy retrieving! ## API ### Options #### `id` A unique identifier for this plugin (`string`, default: `'GoldenRetriever'`). #### `expires` How long to store metadata and files for. Used for `IndexedDB` and, when `window.indexedDB` is not available, `LocalStorage` (`number`, default: `24 * 60 * 60 * 1000` // 24 hours). #### `serviceWorker` Whether to enable `Service Worker` storage (`boolean`, default: `false`). --- Source: https://uppy.io/docs/google-drive # Google Drive The `@uppy/google-drive` plugin lets users import files from their [Google Drive](https://drive.google.com) account. A [Companion](/docs/companion) instance is required for the Google Drive plugin to work. Companion handles authentication with Google Drive, downloads the files, and uploads them to the destination. This saves the user bandwidth, especially helpful if they are on a mobile connection. You can self-host Companion or get a hosted version with any [Transloadit plan](https://transloadit.com/pricing/). Either way you need your own Google OAuth app. Transloadit no longer provides one for Google Drive. :::warning Google Drive needs your own Google OAuth app Transloadit’s shared Google OAuth app is blocked by Google, so the Google Drive plugin does not work on Transloadit-hosted Companion with the default credentials. Users get a Google page that says “This app is blocked”. To use this plugin with hosted Companion you have to register your own Google OAuth app and hand it to Companion as a Transloadit credential, see [Use with Transloadit](/docs/google-drive#use-with-transloadit). The [Google Drive Picker](/docs/google-drive-picker) plugin uses the non-restricted `drive.file` scope, so it needs no Google verification, but it still needs your own Google Cloud client ID, API key and app ID. Background: [Navigating Google’s API changes](https://transloadit.com/blog/2025/02/the-new-google-situation/). ::: ## When should I use this? When you want to let users import files from their [Google Drive](https://drive.google.com) account. You should use this plugin over the [Google Drive Picker plugin](/docs/google-drive-picker) if you prefer a UI with more controls, a leaner bundle size, and a more consistent user experience. The downside is it needs the restricted `drive.readonly` scope. Using that scope in production requires Google’s app verification, which can take months and may involve a third-party CASA Tier 2 security assessment. Until your app is verified, only the test users you list in the Google Cloud console can sign in. This applies whether you self-host Companion or use Transloadit’s hosted one. **NPM** ```shell npm install @uppy/google-drive ``` **Yarn** ```shell yarn add @uppy/google-drive ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use Using Google Drive requires setup in both Uppy and Companion. ### Use in Uppy ```js {10-13} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import GoogleDrive from '@uppy/google-drive'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(GoogleDrive, { companionUrl: 'https://your-companion.com' }); ``` ### Use with Transloadit Transloadit’s own Google OAuth app [no longer works](https://transloadit.com/blog/2025/02/the-new-google-situation/), so hosted Companion can only sign users in to Google Drive with an OAuth app that you register and store as a Transloadit credential. #### 1. Create a Google OAuth app In the [Google Cloud console](https://console.cloud.google.com/): - Create a project (or pick one) and enable the Google Drive API. - Configure the OAuth consent screen and add the scope `https://www.googleapis.com/auth/drive.readonly`. - While the app is unverified, its publishing status is “Testing” and only the test users you add on the consent screen can sign in. Add your own Google account to test with. Production use needs [Google’s verification](https://support.google.com/cloud/answer/13463073) for this restricted scope. - Create an OAuth client ID of type “Web application” and add this authorized redirect URI: ``` https://api2.transloadit.com/companion/drive/redirect ``` Leave “Authorized JavaScript origins” empty. Companion exchanges the authorization code for tokens on the server, and JavaScript origins are only needed for browser-side token flows such as the Google Drive Picker. Google gives you a client ID and a client secret. #### 2. Store it as a Transloadit credential On the [Credentials page](https://transloadit.com/c/template-credentials/) of the Transloadit console, under **Third-party Credentials**, click **New Credential** and fill in: | Field | Value | | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | Service | Companion OAuth | | Name | 3 to 255 characters: letters, digits, dots, dashes or underscores, e.g. `google_drive_own`. You pass this to the plugin as `credentialsName`. | | Provider Name | Google Drive | | Allowed Origins | Optional, can be left empty. | | OAuth Key | The Google client ID | | OAuth Secret | The Google client secret | | Transloadit Gateway URL | Optional. Leave empty unless you run your own Transloadit Gateway (a proxy that white-labels the API endpoints). | :::note Companion 7.0.0 to 7.0.2 rejected an empty gateway URL and login failed with “Could not fetch credentials” (fixed in the next Companion release). If you self-host one of those versions, set the field to your Companion’s public base URL as a workaround. ::: #### 3. Point the plugin at the credential ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import GoogleDrive from '@uppy/google-drive'; uppy.use(GoogleDrive, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', }, }); ``` `companionUrl` has to be `COMPANION_URL`, which is `https://api2.transloadit.com/companion`. Using a regional hostname such as `api2-eu-west-1.transloadit.com` starts the OAuth flow on one host and returns to another, and login fails with “Cannot find state in session”. `key` is your Transloadit API key, not the Google client ID. The plugin sends `key` and `credentialsName` to Companion, which looks up the credential on the Transloadit side when the login popup opens. Nothing is checked before that, so a typo only shows up when a user tries to sign in. Until Google has verified your app’s branding, the consent dialog shows the domain of the redirect URI rather than your app name, so it says “transloadit.com wants to access your Google Account”. After [brand verification](https://support.google.com/cloud/answer/15549049) it shows the app name from your [Google Cloud console](https://console.cloud.google.com/auth/branding). #### Errors you can run into | What the user sees | Cause | | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Google page “This app is blocked” | `companionKeysParams` is missing, so the login used Transloadit’s shared Google app, which some Google accounts (for example those with Advanced Protection) refuse. | | Google page “Access blocked: … has not completed the Google verification process” | Your app is unverified and this Google account is not on its test user list. | | Companion page “Could not fetch credentials” | Wrong `key` or `credentialsName`: the credential could not be looked up in the workspace that `key` belongs to. | | Companion page “Cannot find state in session” | `companionUrl` points at a regional hostname (for example `api2-eu-west-1.transloadit.com`) while the OAuth callback returns through the global `api2.transloadit.com`; the two can land in different regions, and the login session lives in only one of them. | | Requests fail with 401 right after switching credentials | The browser still has an auth token from the earlier login. Sign out in the plugin UI, which clears the stored token, and sign in again. | ### Use with self-hosted Companion To sign up for API keys, go to the [Google Developer Console](https://console.developers.google.com/). Create a project for your app if you don’t have one yet. - On the project’s dashboard, [enable the Google Drive API](https://developers.google.com/drive/api/v3/enable-drive-api). - [Set up OAuth authorization](https://developers.google.com/drive/api/v3/about-auth). - Under scopes, add the `https://www.googleapis.com/auth/drive.readonly` Drive API scope. - This is a restricted scope, so your app must complete Google’s OAuth app verification before anyone other than your test users can sign in. See the [OAuth App Verification Help Center](https://support.google.com/cloud/answer/13463073). The app page has a `"Redirect URIs"` field. Here, add: ``` https://$YOUR_COMPANION_HOST_NAME/drive/redirect ``` Google will give you an OAuth client ID and client secret. Configure the Google key and secret in Companion. With the standalone Companion server, specify environment variables: ```shell export COMPANION_GOOGLE_KEY="Google OAuth client ID" export COMPANION_GOOGLE_SECRET="Google OAuth client secret" ``` When using the Companion Node.js API, configure these options: ```js companion.app({ providerOptions: { drive: { key: 'Google OAuth client ID', secret: 'Google OAuth client secret', }, }, }); ``` ## API ### Options #### `id` A unique identifier for this plugin (`string`, default is a unique ID for each plugin). #### `title` Title / name shown in the UI, such as Dashboard tabs (`string`, default is the name of the plugin). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `companionUrl` URL to a [Companion](/docs/companion) instance (`string`, default: `null`). For Transloadit-hosted Companion use the `COMPANION_URL` constant exported by `@uppy/transloadit`, which is `https://api2.transloadit.com/companion`. Do not use a regional hostname such as `api2-eu-west-1.transloadit.com`: the OAuth flow then starts on one host and returns to another, and login fails with “Cannot find state in session”. #### `companionHeaders` Custom headers that should be sent along to [Companion](/docs/companion) on every request (`Object`, default: `{}`). #### `companionAllowedHosts` The valid and authorised URL(s) from which OAuth responses should be accepted (`string` or `RegExp` or `Array`). This option is useful when you have your [Companion](/docs/companion) running on several hosts. Otherwise, the default value should do fine, which uses the origin of `companionUrl`. This value can be a `string`, a `RegExp` pattern, or an `Array` of these. Strings are evaluated as regular expressions too and will be wrapped in a RegExp like so: ```js new RegExp(`^${value}$`); ``` **Important:** You must escape regex characters like `.`, or you might open your app up to security vulnerabilities. - Example correct strings - `'^(?:.*\\.)?example\.com$'` matches `example.com` and all of its subdomains. - `'https://example\.com'` matches `https://example.com` only. - Example vulnerability: `'https://www.example.com'` would allow an attacker with the domain `wwwxexample.com` to forge and inject a fraudulent token into Uppy. #### `companionKeysParams` Only applies to plugins that sign in through Companion (Google Drive, Dropbox, Box, OneDrive, …). The Google Drive Picker and Google Photos Picker ignore it; they authenticate directly with Google. Google Drive Picker uses its own `clientId`, `apiKey` and `appId`, while Google Photos Picker uses its own `clientId`. Use your own OAuth app with Transloadit-hosted Companion instead of Transloadit’s shared one (`Object`, default: `undefined`). It has two fields: - `key`: your Transloadit API key. - `credentialsName`: the name of a “Companion OAuth” credential you created in the Transloadit console, which holds the provider’s OAuth key and secret. ```js companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', } ``` Before the login popup opens, the plugin sends these values to Companion to obtain a pre-auth token, and Companion fetches the OAuth key and secret from Transloadit when the flow starts. The values are also sent along with every later request in a `uppy-credentials-params` header. Companion does not validate the credential name up front, so a wrong name only fails when a user tries to sign in. On Transloadit-hosted Companion this option is required for Google Drive, see [Google Drive: Use with Transloadit](/docs/google-drive#use-with-transloadit). #### `companionCookiesRule` This option correlates to the [RequestCredentials value](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials) (`string`, default: `'same-origin'`). This tells the plugin whether to send cookies to [Companion](/docs/companion). #### `locale` An object with `strings` property containing additional i18n strings. The key is the i18n key and the value is the English string. Example: ```js { strings: { someKey: 'Some English string', }, } ``` #### `storage` A custom storage to be used for the plugin’s persistent data. Type `AsyncStore`, default is `LocalStorage`. --- Source: https://uppy.io/docs/google-drive-picker # Google Drive Picker The `@uppy/google-drive-picker` plugin lets users import files from their [Google Drive](https://drive.google.com) account using the new [Picker API](https://developers.google.com/drive/picker). A [Companion](/docs/companion) instance is required for the Google Drive Picker plugin to work. Companion downloads the files from Google Drive, and uploads them to the destination. This saves the user bandwidth, especially helpful if they are on a mobile connection. You can self-host Companion or get a hosted version with any [Transloadit plan](https://transloadit.com/pricing/). See also [Google Photos Picker](/docs/google-photos-picker.md). ## When should I use this? When you want to let users import files from their [Google Drive](https://drive.google.com) account. You should use this plugin over our other [Google Drive plugin](/docs/google-drive) if you want to avoid using a restricted API scope, which requires CASA Tier 2 compliance. The downside of using the Picker UI made by Google is less controls, downloading an additional bundle, and a less consistent user experience. **NPM** ```shell npm install @uppy/google-drive-picker ``` **Yarn** ```shell yarn add @uppy/google-drive-picker ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use Using Google Drive Picker requires setup in both Uppy and Companion. ### Prerequisites Make sure your web app is hosted on a server that either does **not set `Cross-Origin-Opener-Policy` at all** or sets it to `same-origin-allow-popups`. ### Initial setup To sign up for API keys, go to the [Google Developer Console](https://console.developers.google.com/). Create a project for your app if you don’t have one yet. - On the project’s dashboard, enable the [Google Picker API](https://console.cloud.google.com/apis/library/picker.googleapis.com) (for Google Drive). - Create an API key: - Application restrictions: _Websites_ - Website restrictions: Add the base URL of the domain name you’re hosting the **frontend web app** on, example: `https://example.com`. Note that if you’re testing locally you need to add `http://localhost:LOCAL_PORT` or similar - API restrictions: Restrict key: Tick _Google Picker API_ - Click _Show key_ and use it as the `apiKey` argument to Uppy. - Create an OAuth 2.0 Client ID of type Web application: - Authorized JavaScript origins: Add the base URL of the domain name you’re hosting the **frontend web app** on, example: `https://example.com`. Note that if you’re testing locally you need to add `http://localhost:LOCAL_PORT` or similar. This will be your `clientId` in Uppy. - For how to find `appId`, [see options below.](#appid) - Some users reported that the [Google Drive API](https://console.cloud.google.com/marketplace/product/google/drive.googleapis.com?q=search&referrer=search) must be enabled as well, so if you’re having problems, please try that. ### Use in Uppy ```js {10-13} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import GoogleDrivePicker from '@uppy/google-drive-picker'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(GoogleDrivePicker, { companionUrl: 'https://your-companion.com', clientId: 'From Google Developer Console', apiKey: 'From Google Developer Console', appId: 'From Google Developer Console', }); ``` ### Use with Transloadit ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import GoogleDrivePicker from '@uppy/google-drive-picker'; uppy.use(GoogleDrivePicker, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, clientId: 'From Google Developer Console', apiKey: 'From Google Developer Console', appId: 'From Google Developer Console', }); ``` ### Use in Companion Companion is used to download/upload the picked files. Companion supports this plugin out-of-the-box, however it must be enabled in Companion with the `enableGooglePickerEndpoint` / `COMPANION_ENABLE_GOOGLE_PICKER_ENDPOINT` option. For this plugin, all credentials are public (non-secret) and provided in the frontend. ## API ### Options #### `id` A unique identifier for this plugin (`string`, default is a unique ID for each plugin). #### `title` Title / name shown in the UI, such as Dashboard tabs (`string`, default is the name of the plugin). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `companionUrl` URL to a [Companion](/docs/companion) instance (`string`, default: `null`). For Transloadit-hosted Companion use the `COMPANION_URL` constant exported by `@uppy/transloadit`, which is `https://api2.transloadit.com/companion`. Do not use a regional hostname such as `api2-eu-west-1.transloadit.com`: the OAuth flow then starts on one host and returns to another, and login fails with “Cannot find state in session”. #### `companionHeaders` Custom headers that should be sent along to [Companion](/docs/companion) on every request (`Object`, default: `{}`). #### `companionAllowedHosts` The valid and authorised URL(s) from which OAuth responses should be accepted (`string` or `RegExp` or `Array`). This option is useful when you have your [Companion](/docs/companion) running on several hosts. Otherwise, the default value should do fine, which uses the origin of `companionUrl`. This value can be a `string`, a `RegExp` pattern, or an `Array` of these. Strings are evaluated as regular expressions too and will be wrapped in a RegExp like so: ```js new RegExp(`^${value}$`); ``` **Important:** You must escape regex characters like `.`, or you might open your app up to security vulnerabilities. - Example correct strings - `'^(?:.*\\.)?example\.com$'` matches `example.com` and all of its subdomains. - `'https://example\.com'` matches `https://example.com` only. - Example vulnerability: `'https://www.example.com'` would allow an attacker with the domain `wwwxexample.com` to forge and inject a fraudulent token into Uppy. #### `companionKeysParams` Only applies to plugins that sign in through Companion (Google Drive, Dropbox, Box, OneDrive, …). The Google Drive Picker and Google Photos Picker ignore it; they authenticate directly with Google. Google Drive Picker uses its own `clientId`, `apiKey` and `appId`, while Google Photos Picker uses its own `clientId`. Use your own OAuth app with Transloadit-hosted Companion instead of Transloadit’s shared one (`Object`, default: `undefined`). It has two fields: - `key`: your Transloadit API key. - `credentialsName`: the name of a “Companion OAuth” credential you created in the Transloadit console, which holds the provider’s OAuth key and secret. ```js companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', } ``` Before the login popup opens, the plugin sends these values to Companion to obtain a pre-auth token, and Companion fetches the OAuth key and secret from Transloadit when the flow starts. The values are also sent along with every later request in a `uppy-credentials-params` header. Companion does not validate the credential name up front, so a wrong name only fails when a user tries to sign in. On Transloadit-hosted Companion this option is required for Google Drive, see [Google Drive: Use with Transloadit](/docs/google-drive#use-with-transloadit). #### `companionCookiesRule` This option correlates to the [RequestCredentials value](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials) (`string`, default: `'same-origin'`). This tells the plugin whether to send cookies to [Companion](/docs/companion). #### `locale` An object with `strings` property containing additional i18n strings. The key is the i18n key and the value is the English string. Example: ```js { strings: { someKey: 'Some English string', }, } ``` #### `storage` A custom storage to be used for the plugin’s persistent data. Type `AsyncStore`, default is `LocalStorage`. #### `clientId` The client ID from the [Initial setup](#initial-setup) (`string`). #### `apiKey` The API key from the [Initial setup](#initial-setup) (`string`). #### `appId` The App ID can be found in the [Google Developer Console](https://console.developers.google.com): _Project number_ under [`IAM & Admin` > `Settings`](https://console.cloud.google.com/iam-admin/settings). :::note Make sure you use the **project number** (**not** project ID or project name), and make sure you’re in the correct project. Note that if this is set to the wrong value it will be ignored by Google when your project is in testing mode, but once in production users will get 404 errors when trying to download. ::: --- Source: https://uppy.io/docs/google-photos-picker # Google Photos Picker The `@uppy/google-photos-picker` plugin lets users import files from their [Google Drive](https://drive.google.com) account using the new [Picker API](https://developers.google.com/photos/picker). A [Companion](/docs/companion) instance is required for the Google Drive Picker plugin to work. Companion downloads the files from Google Drive, and uploads them to the destination. This saves the user bandwidth, especially helpful if they are on a mobile connection. You can self-host Companion or get a hosted version with any [Transloadit plan](https://transloadit.com/pricing/). See also [Google Drive Picker](/docs/google-drive-picker.md). ## When should I use this? When you want to let users import files from their [Google Photos](https://photos.google.com) account. **NPM** ```shell npm install @uppy/google-photos-picker ``` **Yarn** ```shell yarn add @uppy/google-photos-picker ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use Using Google Photos Picker requires setup in both Uppy and Companion. ### Initial setup To sign up for API keys, go to the [Google Developer Console](https://console.developers.google.com/). Create a project for your app if you don’t have one yet. - On the project’s dashboard, enable the [Google Photos Picker API](https://console.cloud.google.com/apis/library/photospicker.googleapis.com). - Create an OAuth 2.0 Client ID of type Web application with the correct Authorized JavaScript origins. This will be your `clientId` in Uppy. ### Use in Uppy ```js {10-13} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import GooglePhotosPicker from '@uppy/google-photos-picker'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(GooglePhotosPicker, { companionUrl: 'https://your-companion.com', clientId: 'From Google Developer Console', }); ``` ### Use with Transloadit ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import GooglePhotosPicker from '@uppy/google-photos-picker'; uppy.use(GooglePhotosPicker, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, clientId: 'From Google Developer Console', }); ``` ### Use in Companion Companion is used to download/upload the picked files. Companion supports this plugin out-of-the-box, however it must be enabled in Companion with the `enableGooglePickerEndpoint` / `COMPANION_ENABLE_GOOGLE_PICKER_ENDPOINT` option. For this plugin, all credentials are public (non-secret) and provided in the frontend. ## API ### Options #### `id` A unique identifier for this plugin (`string`, default is a unique ID for each plugin). #### `title` Title / name shown in the UI, such as Dashboard tabs (`string`, default is the name of the plugin). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `companionUrl` URL to a [Companion](/docs/companion) instance (`string`, default: `null`). For Transloadit-hosted Companion use the `COMPANION_URL` constant exported by `@uppy/transloadit`, which is `https://api2.transloadit.com/companion`. Do not use a regional hostname such as `api2-eu-west-1.transloadit.com`: the OAuth flow then starts on one host and returns to another, and login fails with “Cannot find state in session”. #### `companionHeaders` Custom headers that should be sent along to [Companion](/docs/companion) on every request (`Object`, default: `{}`). #### `companionAllowedHosts` The valid and authorised URL(s) from which OAuth responses should be accepted (`string` or `RegExp` or `Array`). This option is useful when you have your [Companion](/docs/companion) running on several hosts. Otherwise, the default value should do fine, which uses the origin of `companionUrl`. This value can be a `string`, a `RegExp` pattern, or an `Array` of these. Strings are evaluated as regular expressions too and will be wrapped in a RegExp like so: ```js new RegExp(`^${value}$`); ``` **Important:** You must escape regex characters like `.`, or you might open your app up to security vulnerabilities. - Example correct strings - `'^(?:.*\\.)?example\.com$'` matches `example.com` and all of its subdomains. - `'https://example\.com'` matches `https://example.com` only. - Example vulnerability: `'https://www.example.com'` would allow an attacker with the domain `wwwxexample.com` to forge and inject a fraudulent token into Uppy. #### `companionKeysParams` Only applies to plugins that sign in through Companion (Google Drive, Dropbox, Box, OneDrive, …). The Google Drive Picker and Google Photos Picker ignore it; they authenticate directly with Google. Google Drive Picker uses its own `clientId`, `apiKey` and `appId`, while Google Photos Picker uses its own `clientId`. Use your own OAuth app with Transloadit-hosted Companion instead of Transloadit’s shared one (`Object`, default: `undefined`). It has two fields: - `key`: your Transloadit API key. - `credentialsName`: the name of a “Companion OAuth” credential you created in the Transloadit console, which holds the provider’s OAuth key and secret. ```js companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', } ``` Before the login popup opens, the plugin sends these values to Companion to obtain a pre-auth token, and Companion fetches the OAuth key and secret from Transloadit when the flow starts. The values are also sent along with every later request in a `uppy-credentials-params` header. Companion does not validate the credential name up front, so a wrong name only fails when a user tries to sign in. On Transloadit-hosted Companion this option is required for Google Drive, see [Google Drive: Use with Transloadit](/docs/google-drive#use-with-transloadit). #### `companionCookiesRule` This option correlates to the [RequestCredentials value](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials) (`string`, default: `'same-origin'`). This tells the plugin whether to send cookies to [Companion](/docs/companion). #### `locale` An object with `strings` property containing additional i18n strings. The key is the i18n key and the value is the English string. Example: ```js { strings: { someKey: 'Some English string', }, } ``` #### `storage` A custom storage to be used for the plugin’s persistent data. Type `AsyncStore`, default is `LocalStorage`. #### `clientId` The client ID from the [Initial setup](#initial-setup) (`string`). --- Source: https://uppy.io/docs/image-editor # Image editor Image editor. Designed to be used with the Dashboard UI.
![Screenshot of the Image Editor plugin UI in Dashboard](https://user-images.githubusercontent.com/1199054/87208710-654db400-c307-11ea-9471-6e3c6582d2a5.png)
## When should I use this? When you want to allow users to crop, rotate, zoom and flip images that are added to Uppy. ## Install **NPM** ```shell npm install @uppy/core @uppy/dashboard @uppy/image-editor ``` **Yarn** ```shell yarn add @uppy/core @uppy/dashboard @uppy/image-editor ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js {3,7,11} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import ImageEditor from '@uppy/image-editor'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; import '@uppy/image-editor/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(ImageEditor); ``` ## API ### Options :::info If you automatically want to open the image editor when an image is added, see the [`autoOpen`](/docs/dashboard#autoopen) Dashboard option. ::: #### `id` A unique identifier for this plugin (`string`, default: `'ImageEditor'`). #### `quality` Quality Of the resulting blob that will be saved in Uppy after editing/cropping (`number`, default: `0.8`). #### `cropperOptions` Image Editor is using the excellent [Cropper.js](https://fengyuanchen.github.io/cropperjs/). `cropperOptions` will be directly passed to `Cropper` and thus can expect the same values as documented in their [README](https://github.com/fengyuanchen/cropperjs/blob/HEAD/README.md#options), with the addition of `croppedCanvasOptions`, which will be passed to [`getCroppedCanvas`](https://github.com/fengyuanchen/cropperjs/blob/HEAD/README.md#getcroppedcanvasoptions). #### `actions` Show action buttons (`Object` or `boolean`). If you you’d like to hide all actions, pass `false` to it. By default all the actions are visible. Or enable/disable them individually: ```js { revert: true, rotate: true, granularRotate: true, flip: true, zoomIn: true, zoomOut: true, cropSquare: true, cropWidescreen: true, cropWidescreenVertical: true, } ``` #### `locale: {}` ```js export default { strings: { revert: 'Revert', rotate: 'Rotate', zoomIn: 'Zoom in', zoomOut: 'Zoom out', flipHorizontal: 'Flip horizontal', aspectRatioSquare: 'Crop square', aspectRatioLandscape: 'Crop landscape (16:9)', aspectRatioPortrait: 'Crop portrait (9:16)', }, }; ``` ### Events :::info You can use [`on`](/docs/uppy#onevent-action) and [`once`](/docs/uppy#onceevent-action) to listen to these events. ::: #### `file-editor:start` Emitted when `selectFile(file)` is called. ```js uppy.on('file-editor:start', (file) => { console.log(file); }); ``` #### `file-editor:complete` Emitted after `save(blob)` is called. ```js uppy.on('file-editor:complete', (updatedFile) => { console.log(updatedFile); }); ``` #### `file-editor:cancel` Emitted when `uninstall` is called or when the current image editing changes are discarded. ```js uppy.on('file-editor:cancel', (file) => { console.log(file); }); ``` --- Source: https://uppy.io/docs/url # Import from URL The `@uppy/url` plugin allows users to import files from the internet. Paste any URL and it will be added! :::tip [Try out the live example](/examples) or take it for a spin in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-zaqyaf?file=main.js). ::: ## When should I use this? When you want to let users import files any URL. A [Companion](/docs/companion) instance is required for the URL plugin to work. This saves the user bandwidth, especially helpful if they are on a mobile connection. You can self-host Companion or get a hosted version with any [Transloadit plan](https://transloadit.com/pricing/). :::note Companion has [Server Side Request Forgery](https://owasp.org/www-community/attacks/Server_Side_Request_Forgery) (SSRF) protections built-in so you don’t have to worry about the security implications of arbitrary URLs. ::: **NPM** ```shell npm install @uppy/url ``` **Yarn** ```shell yarn add @uppy/url ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use Using `@uppy/url` only requires setup in Uppy. ### Use in Uppy ```js {10-13} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import Url from '@uppy/url'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; import '@uppy/url/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(Url, { companionUrl: 'https://your-companion.com' }); ``` ### Use with Transloadit ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Url from '@uppy/url'; uppy.use(Url, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }); ``` You may also hit rate limits, because the OAuth application is shared between everyone using Transloadit. To solve that, you can use your own OAuth keys with Transloadit’s hosted Companion servers by using Transloadit Template Credentials. [Create a Template Credential][template-credentials] on the Transloadit site. Select “Companion OAuth” for the service, and enter the key and secret for the provider you want to use. Then you can pass the name of the new credentials to that provider: ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Url from '@uppy/url'; uppy.use(Url, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'my_companion_dropbox_creds', }, }); ``` ### Use in Companion Companion supports this plugin out-of-the-box, however it must be enabled in Companion with the `enableUrlEndpoint` / `COMPANION_ENABLE_URL_ENDPOINT` option. ## API ### Options #### `id` A unique identifier for this plugin (`string`, default is a unique ID for each plugin). #### `title` Title / name shown in the UI, such as Dashboard tabs (`string`, default is the name of the plugin). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `companionUrl` URL to a [Companion](/docs/companion) instance (`string`, default: `null`). For Transloadit-hosted Companion use the `COMPANION_URL` constant exported by `@uppy/transloadit`, which is `https://api2.transloadit.com/companion`. Do not use a regional hostname such as `api2-eu-west-1.transloadit.com`: the OAuth flow then starts on one host and returns to another, and login fails with “Cannot find state in session”. #### `companionHeaders` Custom headers that should be sent along to [Companion](/docs/companion) on every request (`Object`, default: `{}`). #### `companionAllowedHosts` The valid and authorised URL(s) from which OAuth responses should be accepted (`string` or `RegExp` or `Array`). This option is useful when you have your [Companion](/docs/companion) running on several hosts. Otherwise, the default value should do fine, which uses the origin of `companionUrl`. This value can be a `string`, a `RegExp` pattern, or an `Array` of these. Strings are evaluated as regular expressions too and will be wrapped in a RegExp like so: ```js new RegExp(`^${value}$`); ``` **Important:** You must escape regex characters like `.`, or you might open your app up to security vulnerabilities. - Example correct strings - `'^(?:.*\\.)?example\.com$'` matches `example.com` and all of its subdomains. - `'https://example\.com'` matches `https://example.com` only. - Example vulnerability: `'https://www.example.com'` would allow an attacker with the domain `wwwxexample.com` to forge and inject a fraudulent token into Uppy. #### `companionKeysParams` Only applies to plugins that sign in through Companion (Google Drive, Dropbox, Box, OneDrive, …). The Google Drive Picker and Google Photos Picker ignore it; they authenticate directly with Google. Google Drive Picker uses its own `clientId`, `apiKey` and `appId`, while Google Photos Picker uses its own `clientId`. Use your own OAuth app with Transloadit-hosted Companion instead of Transloadit’s shared one (`Object`, default: `undefined`). It has two fields: - `key`: your Transloadit API key. - `credentialsName`: the name of a “Companion OAuth” credential you created in the Transloadit console, which holds the provider’s OAuth key and secret. ```js companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', } ``` Before the login popup opens, the plugin sends these values to Companion to obtain a pre-auth token, and Companion fetches the OAuth key and secret from Transloadit when the flow starts. The values are also sent along with every later request in a `uppy-credentials-params` header. Companion does not validate the credential name up front, so a wrong name only fails when a user tries to sign in. On Transloadit-hosted Companion this option is required for Google Drive, see [Google Drive: Use with Transloadit](/docs/google-drive#use-with-transloadit). #### `companionCookiesRule` This option correlates to the [RequestCredentials value](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials) (`string`, default: `'same-origin'`). This tells the plugin whether to send cookies to [Companion](/docs/companion). #### `locale` An object with `strings` property containing additional i18n strings. The key is the i18n key and the value is the English string. Example: ```js { strings: { someKey: 'Some English string', }, } ``` #### `storage` A custom storage to be used for the plugin’s persistent data. Type `AsyncStore`, default is `LocalStorage`. [template-credentials]: https://transloadit.com/docs/topics/template-credentials/ --- Source: https://uppy.io/docs/webdav # Import from WebDAV WebDAV (Web Distributed Authoring and Versioning) is an extension of the HTTP protocol that enables users to manage files on remote servers. It supports uploading, downloading, editing, and organizing files over the web, making it a versatile option for remote file storage and collaboration. ## When should I use this? When you want to let users import files from any WebDAV supported service, such as Nextcloud, OwnCloud, and Box. This plugin only supports public WebDAV URLs. Some providers offer WebDAV with OAuth, which is not supported. A [Companion](/docs/companion) instance is required for the WebDAV plugin to work. This saves the user bandwidth, especially helpful if they are on a mobile connection. You can self-host Companion or get a hosted version with any [Transloadit plan](https://transloadit.com/pricing/). :::note Companion has [Server Side Request Forgery](https://owasp.org/www-community/attacks/Server_Side_Request_Forgery) (SSRF) protections built-in so you don’t have to worry about the security implications of arbitrary URLs. ::: **NPM** ```shell npm install @uppy/webdav ``` **Yarn** ```shell yarn add @uppy/webdav ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js {10-13} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import WebDav from '@uppy/webdav'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(WebDav, { companionUrl: 'https://your-companion.com' }); ``` ## API ### Options #### `id` A unique identifier for this plugin (`string`, default is a unique ID for each plugin). #### `title` Title / name shown in the UI, such as Dashboard tabs (`string`, default is the name of the plugin). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `companionUrl` URL to a [Companion](/docs/companion) instance (`string`, default: `null`). For Transloadit-hosted Companion use the `COMPANION_URL` constant exported by `@uppy/transloadit`, which is `https://api2.transloadit.com/companion`. Do not use a regional hostname such as `api2-eu-west-1.transloadit.com`: the OAuth flow then starts on one host and returns to another, and login fails with “Cannot find state in session”. #### `companionHeaders` Custom headers that should be sent along to [Companion](/docs/companion) on every request (`Object`, default: `{}`). #### `companionAllowedHosts` The valid and authorised URL(s) from which OAuth responses should be accepted (`string` or `RegExp` or `Array`). This option is useful when you have your [Companion](/docs/companion) running on several hosts. Otherwise, the default value should do fine, which uses the origin of `companionUrl`. This value can be a `string`, a `RegExp` pattern, or an `Array` of these. Strings are evaluated as regular expressions too and will be wrapped in a RegExp like so: ```js new RegExp(`^${value}$`); ``` **Important:** You must escape regex characters like `.`, or you might open your app up to security vulnerabilities. - Example correct strings - `'^(?:.*\\.)?example\.com$'` matches `example.com` and all of its subdomains. - `'https://example\.com'` matches `https://example.com` only. - Example vulnerability: `'https://www.example.com'` would allow an attacker with the domain `wwwxexample.com` to forge and inject a fraudulent token into Uppy. #### `companionKeysParams` Only applies to plugins that sign in through Companion (Google Drive, Dropbox, Box, OneDrive, …). The Google Drive Picker and Google Photos Picker ignore it; they authenticate directly with Google. Google Drive Picker uses its own `clientId`, `apiKey` and `appId`, while Google Photos Picker uses its own `clientId`. Use your own OAuth app with Transloadit-hosted Companion instead of Transloadit’s shared one (`Object`, default: `undefined`). It has two fields: - `key`: your Transloadit API key. - `credentialsName`: the name of a “Companion OAuth” credential you created in the Transloadit console, which holds the provider’s OAuth key and secret. ```js companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', } ``` Before the login popup opens, the plugin sends these values to Companion to obtain a pre-auth token, and Companion fetches the OAuth key and secret from Transloadit when the flow starts. The values are also sent along with every later request in a `uppy-credentials-params` header. Companion does not validate the credential name up front, so a wrong name only fails when a user tries to sign in. On Transloadit-hosted Companion this option is required for Google Drive, see [Google Drive: Use with Transloadit](/docs/google-drive#use-with-transloadit). #### `companionCookiesRule` This option correlates to the [RequestCredentials value](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials) (`string`, default: `'same-origin'`). This tells the plugin whether to send cookies to [Companion](/docs/companion). #### `locale` An object with `strings` property containing additional i18n strings. The key is the i18n key and the value is the English string. Example: ```js { strings: { someKey: 'Some English string', }, } ``` #### `storage` A custom storage to be used for the plugin’s persistent data. Type `AsyncStore`, default is `LocalStorage`. --- Source: https://uppy.io/docs/informer # Informer ::::caution Deprecated As of Uppy 5.0, `@uppy/informer` was merged into [`@uppy/dashboard`](/docs/dashboard/). Use Dashboard’s built-in notifications triggered via [`uppy.info()`](/docs/uppy#infomessage-type-duration). See the migration notes in the [migration guide](/docs/guides/migration-guides/). :::: The `@uppy/informer` plugin is a pop-up bar for showing notifications for the [Dashboard](/docs/dashboard). When plugins have some exciting news (or errors) to share, they can with Informer ## When should I use it? When you use the [Dashboard](/docs/dashboard) it’s already included by default. This plugin is published separately but made specifically for the Dashboard. You can technically use it without it, but it’s not officially supported. ## Install **NPM** ```shell npm install @uppy/informer ``` **Yarn** ```shell yarn add @uppy/informer ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js import Uppy from '@uppy/core'; import Informer from '@uppy/informer'; // The `@uppy/informer` plugin includes some basic styles. // You can also choose not to use it and provide your own styles instead. import '@uppy/core/css/style.min.css'; import '@uppy/informer/css/style.min.css'; new Uppy().use(Informer, { target: '#informer' }); ``` Informer gets its data from `uppy.state.info`, which is updated by various plugins via [`uppy.info`](/docs/uppy#infomessage-type-duration) method. In the [compressor](/docs/compressor) plugin we use it like this for instance: ```js const size = prettierBytes(totalCompressedSize); this.uppy.info(this.i18n('compressedX', { size }), 'info'); ``` When calling `uppy.info`, [Uppy](/docs/uppy) emits [`info-visible`](/docs/uppy#info-visible) and will emit [`info-hidden`](/docs/uppy#info-hidden) after the timeout. ## API ### Options ### `id` A unique identifier for this plugin (`string`, default: `'Informer'`). Use this if you need several `Informer` instances. ### `target` DOM element, CSS selector, or plugin to mount the Informer into (`string` or `Element`, default: `null`). --- Source: https://uppy.io/docs/locales # Internationalisation Uppy speaks many languages, English being the default. You can use a locale pack to translate Uppy into your language of choice. :::tip Checkout [`@uppy/locales`](https://github.com/transloadit/uppy/tree/main/packages/%40uppy/locales) on GitHub to see the list of supported languages. ::: ## Using a locale pack from npm This is the recommended way. Install `@uppy/locales` package from npm, then choose the locale you’d like to use: `@uppy/locales/lib/LANGUAGE_CODE`. ```bash npm i @uppy/core @uppy/locales ``` ```js import Uppy from '@uppy/core'; import German from '@uppy/locales/lib/de_DE'; // see below for the full list of locales const uppy = new Uppy({ debug: true, locale: German, }); ``` ## Using a locale pack from CDN Add a ` ``` ## Overriding locale strings for a specific plugin Many plugins come with their own locale strings, and the packs we provide consist of most of those strings. You can, however, override a locale string for a specific plugin, regardless of whether you are using locale pack or not. See the plugin documentation for the list of locale strings it uses. ```js import Uppy from '@uppy/core'; import DragDrop from '@uppy/drag-drop'; import Russian from '@uppy/locales/lib/ru_RU'; const uppy = new Uppy({ debug: true, autoProceed: true, locale: Russian, }); uppy.use(DragDrop, { target: '.UppyDragDrop', // We are using the ru_RU locale pack (set above in Uppy options), // but you can also override specific strings like so: locale: { strings: { browse: 'выберите ;-)', }, }, }); ``` ## List of locales
38 Locales NPM CDN Source on GitHub
Arabic Saudi Arabia [ @uppy/locales/lib/ar_SA ](https://www.npmjs.com/package/@uppy/locales) [ ar_SA.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/ar_SA.min.js) [ ar_SA.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/ar_SA.ts)
Bulgarian Bulgaria [ @uppy/locales/lib/bg_BG ](https://www.npmjs.com/package/@uppy/locales) [ bg_BG.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/bg_BG.min.js) [ bg_BG.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/bg_BG.ts)
Chinese China [ @uppy/locales/lib/zh_CN ](https://www.npmjs.com/package/@uppy/locales) [ zh_CN.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/zh_CN.min.js) [ zh_CN.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/zh_CN.ts)
Chinese Taiwan [ @uppy/locales/lib/zh_TW ](https://www.npmjs.com/package/@uppy/locales) [ zh_TW.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/zh_TW.min.js) [ zh_TW.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/zh_TW.ts)
Croatian Croatia [ @uppy/locales/lib/hr_HR ](https://www.npmjs.com/package/@uppy/locales) [ hr_HR.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/hr_HR.min.js) [ hr_HR.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/hr_HR.ts)
Czech Czechia [ @uppy/locales/lib/cs_CZ ](https://www.npmjs.com/package/@uppy/locales) [ cs_CZ.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/cs_CZ.min.js) [ cs_CZ.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/cs_CZ.ts)
Danish Denmark [ @uppy/locales/lib/da_DK ](https://www.npmjs.com/package/@uppy/locales) [ da_DK.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/da_DK.min.js) [ da_DK.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/da_DK.ts)
Dutch Netherlands [ @uppy/locales/lib/nl_NL ](https://www.npmjs.com/package/@uppy/locales) [ nl_NL.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/nl_NL.min.js) [ nl_NL.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/nl_NL.ts)
English United States [ @uppy/locales/lib/en_US ](https://www.npmjs.com/package/@uppy/locales) [ en_US.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/en_US.min.js) [ en_US.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/en_US.ts)
Finnish Finland [ @uppy/locales/lib/fi_FI ](https://www.npmjs.com/package/@uppy/locales) [ fi_FI.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/fi_FI.min.js) [ fi_FI.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/fi_FI.ts)
French France [ @uppy/locales/lib/fr_FR ](https://www.npmjs.com/package/@uppy/locales) [ fr_FR.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/fr_FR.min.js) [ fr_FR.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/fr_FR.ts)
Galician Spain [ @uppy/locales/lib/gl_ES ](https://www.npmjs.com/package/@uppy/locales) [ gl_ES.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/gl_ES.min.js) [ gl_ES.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/gl_ES.ts)
German Germany [ @uppy/locales/lib/de_DE ](https://www.npmjs.com/package/@uppy/locales) [ de_DE.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/de_DE.min.js) [ de_DE.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/de_DE.ts)
Greek Greece [ @uppy/locales/lib/el_GR ](https://www.npmjs.com/package/@uppy/locales) [ el_GR.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/el_GR.min.js) [ el_GR.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/el_GR.ts)
Hebrew Israel [ @uppy/locales/lib/he_IL ](https://www.npmjs.com/package/@uppy/locales) [ he_IL.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/he_IL.min.js) [ he_IL.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/he_IL.ts)
Hindi India [ @uppy/locales/lib/hi_IN ](https://www.npmjs.com/package/@uppy/locales) [ hi_IN.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/hi_IN.min.js) [ hi_IN.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/hi_IN.ts)
Hungarian Hungary [ @uppy/locales/lib/hu_HU ](https://www.npmjs.com/package/@uppy/locales) [ hu_HU.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/hu_HU.min.js) [ hu_HU.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/hu_HU.ts)
Icelandic Iceland [ @uppy/locales/lib/is_IS ](https://www.npmjs.com/package/@uppy/locales) [ is_IS.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/is_IS.min.js) [ is_IS.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/is_IS.ts)
Indonesian Indonesia [ @uppy/locales/lib/id_ID ](https://www.npmjs.com/package/@uppy/locales) [ id_ID.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/id_ID.min.js) [ id_ID.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/id_ID.ts)
Italian Italy [ @uppy/locales/lib/it_IT ](https://www.npmjs.com/package/@uppy/locales) [ it_IT.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/it_IT.min.js) [ it_IT.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/it_IT.ts)
Japanese Japan [ @uppy/locales/lib/ja_JP ](https://www.npmjs.com/package/@uppy/locales) [ ja_JP.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/ja_JP.min.js) [ ja_JP.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/ja_JP.ts)
Korean South Korea [ @uppy/locales/lib/ko_KR ](https://www.npmjs.com/package/@uppy/locales) [ ko_KR.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/ko_KR.min.js) [ ko_KR.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/ko_KR.ts)
Norwegian Bokmål Norway [ @uppy/locales/lib/nb_NO ](https://www.npmjs.com/package/@uppy/locales) [ nb_NO.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/nb_NO.min.js) [ nb_NO.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/nb_NO.ts)
Persian Iran [ @uppy/locales/lib/fa_IR ](https://www.npmjs.com/package/@uppy/locales) [ fa_IR.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/fa_IR.min.js) [ fa_IR.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/fa_IR.ts)
Polish Poland [ @uppy/locales/lib/pl_PL ](https://www.npmjs.com/package/@uppy/locales) [ pl_PL.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/pl_PL.min.js) [ pl_PL.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/pl_PL.ts)
Portuguese Brazil [ @uppy/locales/lib/pt_BR ](https://www.npmjs.com/package/@uppy/locales) [ pt_BR.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/pt_BR.min.js) [ pt_BR.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/pt_BR.ts)
Portuguese Portugal [ @uppy/locales/lib/pt_PT ](https://www.npmjs.com/package/@uppy/locales) [ pt_PT.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/pt_PT.min.js) [ pt_PT.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/pt_PT.ts)
Romanian Romania [ @uppy/locales/lib/ro_RO ](https://www.npmjs.com/package/@uppy/locales) [ ro_RO.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/ro_RO.min.js) [ ro_RO.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/ro_RO.ts)
Russian Russia [ @uppy/locales/lib/ru_RU ](https://www.npmjs.com/package/@uppy/locales) [ ru_RU.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/ru_RU.min.js) [ ru_RU.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/ru_RU.ts)
Serbian Serbia (Cyrillic) [ @uppy/locales/lib/sr_RS_Cyrillic ](https://www.npmjs.com/package/@uppy/locales) [ sr_RS_Cyrillic.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/sr_RS_Cyrillic.min.js) [ sr_RS_Cyrillic.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/sr_RS_Cyrillic.ts)
Serbian Serbia (Latin) [ @uppy/locales/lib/sr_RS_Latin ](https://www.npmjs.com/package/@uppy/locales) [ sr_RS_Latin.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/sr_RS_Latin.min.js) [ sr_RS_Latin.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/sr_RS_Latin.ts)
Slovak Slovakia [ @uppy/locales/lib/sk_SK ](https://www.npmjs.com/package/@uppy/locales) [ sk_SK.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/sk_SK.min.js) [ sk_SK.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/sk_SK.ts)
Spanish Spain [ @uppy/locales/lib/es_ES ](https://www.npmjs.com/package/@uppy/locales) [ es_ES.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/es_ES.min.js) [ es_ES.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/es_ES.ts)
Spanish Mexico [ @uppy/locales/lib/es_MX ](https://www.npmjs.com/package/@uppy/locales) [ es_MX.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/es_MX.min.js) [ es_MX.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/es_MX.ts)
Swedish Sweden [ @uppy/locales/lib/sv_SE ](https://www.npmjs.com/package/@uppy/locales) [ sv_SE.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/sv_SE.min.js) [ sv_SE.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/sv_SE.ts)
Thai Thailand [ @uppy/locales/lib/th_TH ](https://www.npmjs.com/package/@uppy/locales) [ th_TH.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/th_TH.min.js) [ th_TH.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/th_TH.ts)
Turkish Turkey [ @uppy/locales/lib/tr_TR ](https://www.npmjs.com/package/@uppy/locales) [ tr_TR.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/tr_TR.min.js) [ tr_TR.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/tr_TR.ts)
Ukrainian Ukraine [ @uppy/locales/lib/uk_UA ](https://www.npmjs.com/package/@uppy/locales) [ uk_UA.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/uk_UA.min.js) [ uk_UA.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/uk_UA.ts)
Uzbek Uzbekistan [ @uppy/locales/lib/uz_UZ ](https://www.npmjs.com/package/@uppy/locales) [ uz_UZ.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/uz_UZ.min.js) [ uz_UZ.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/uz_UZ.ts)
Vietnamese Vietnam [ @uppy/locales/lib/vi_VN ](https://www.npmjs.com/package/@uppy/locales) [ vi_VN.min.js ](https://releases.transloadit.com/uppy/locales/v3.3.1/vi_VN.min.js) [ vi_VN.ts ](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/locales/src/vi_VN.ts)
## Adding a new language string If you want to add a new locale string to use from Uppy code, add it to [locale.ts](https://github.com/transloadit/uppy/blob/main/packages/%40uppy/status-bar/src/locale.ts) and then run `yarn build`. ## Contributing a new language If you speak a language we don’t yet support, you can contribute! Here’s how you do it: 1. Go to the [uppy/locales](https://github.com/transloadit/uppy/tree/main/packages/%40uppy/locales/src) directory in the Uppy GitHub repo. 2. Go to `en_US.js` and copy its contents, as English is the most up-to-date locale. 3. Press “Create new file”, name it according to the [`language_COUNTRY` format](http://www.i18nguy.com/unicode/language-identifiers.html), make sure to use underscore `_` as a divider. Examples: `en_US`, `en_GB`, `ru_RU`, `ar_AE`. Variants should be trailing, for example `sr_RS_Latin` for Serbian Latin vs Cyrillic. 4. If your language has different pluralization rules than English, update the `pluralize` implementation. If you are unsure how to do this, please ask us for help in a [GitHub issue](https://github.com/transloadit/uppy/issues/new). 5. Paste what you’ve copied from `en_US.js` and use it as a starting point to translate strings into your language. 6. When you are ready, save the file — this should create a PR that we’ll then review 🎉 Thanks! --- Source: https://uppy.io/docs/guides/migration-guides # Migration guides These cover all the major Uppy versions and how to migrate to them. ## Migrate from Uppy 5.x to 6.x ### Four packages merged into `@uppy/core` `@uppy/utils`, `@uppy/store-default`, `@uppy/companion-client`, and `@uppy/provider-views` are now part of `@uppy/core` and are reached through subpath exports. Their existing releases stay on npm but are deprecated: no new versions will be published. | Removed package | New import | | ------------------------ | ----------------------------- | | `@uppy/utils` | `@uppy/core/utils` | | `@uppy/store-default` | `@uppy/core/store-default` | | `@uppy/companion-client` | `@uppy/core/companion-client` | | `@uppy/provider-views` | `@uppy/core/provider-views` | ```diff - import { fetcher } from '@uppy/utils'; + import { fetcher } from '@uppy/core/utils'; - import { RequestClient } from '@uppy/companion-client'; + import { RequestClient } from '@uppy/core/companion-client'; - import DefaultStore from '@uppy/store-default'; + import DefaultStore from '@uppy/core/store-default'; ``` `DefaultStore` stays a default export, `fetcher` and `RequestClient` stay named exports. **Migration steps:** 1. Update the imports as per the table. 2. Remove the four packages from your `package.json`. Every Uppy plugin already depends on `@uppy/core`, so there is one source of truth instead of a sub-dependency your lockfile can pin to an older copy. #### CSS The provider styles moved with the code: | Old | New | | ---------------------------------------- | --------------------------------------------- | | `@uppy/provider-views/css/style.min.css` | `@uppy/core/provider-views/css/style.min.css` | | `@uppy/provider-views/css/style.css` | `@uppy/core/provider-views/css/style.css` | Most apps don’t import this directly. It ships bundled in `@uppy/dashboard`’s CSS. Only change it if you imported the provider-views stylesheet explicitly. #### Types `RequestOptions` moved from `@uppy/utils` to `@uppy/core/companion-client`, where it lives next to `RequestClient`: ```diff - import type { RequestOptions } from '@uppy/utils'; + import type { RequestOptions } from '@uppy/core/companion-client'; ``` `CompanionClientProvider` and `CompanionClientSearchProvider` are removed. They were hand-maintained stand-ins that existed only because `@uppy/utils` could not see the real provider classes. Import `Provider` (or `SearchProvider` in place of `CompanionClientSearchProvider`) instead. Both are _named_ exports: ```diff - import type { CompanionClientProvider } from '@uppy/utils'; + import type { Provider } from '@uppy/core/companion-client'; - const provider: CompanionClientProvider = createProvider(); + const provider: Provider = createProvider(); - import type { CompanionClientSearchProvider } from '@uppy/utils'; + import type { SearchProvider } from '@uppy/core/companion-client'; ``` `UnknownProviderPlugin['provider']` and `UnknownSearchProviderPlugin['provider']` are typed as structural subsets of `Provider` and `SearchProvider` (through `Pick`), so a custom provider that matches the public surface still fits without subclassing either class. #### `isTouchDevice` is removed The move was not wholesale. `isTouchDevice` was deleted outright, not moved to `@uppy/core/utils`. Inline it if you used it: ```js const isTouchDevice = () => 'ontouchstart' in window || navigator.maxTouchPoints > 0; ``` #### The `uppy` meta-package: no change If you use the meta-package or the CDN bundle, nothing changes. `server`, `views.ProviderView`, and `DefaultStore` keep their names and are repointed at the `@uppy/core` subpaths internally: ```js import { DefaultStore, server, Uppy, views } from 'uppy'; // still works // window.Uppy.DefaultStore still works ``` ### `@uppy/aws-s3` rewritten `@uppy/aws-s3` has been rewritten on top of a standalone S3 client. Most options you passed in 5.x are gone (the full lists are below). Configuration is now three mutually exclusive signing modes: - `getCredentials`: client-side SigV4 signing with temporary credentials. - `signRequest`: bring your own signer, client side or server side. - `companionEndpoint`: Companion signs, as before. All three work against any S3-compatible service (R2, MinIO, DigitalOcean Spaces). Client-side signing previously hardcoded `*.amazonaws.com` and could only target AWS. #### Companion: `endpoint` becomes `companionEndpoint` ```diff uppy.use(AwsS3, { - endpoint: 'https://companion.example.com', - headers: { authorization: `Bearer ${token}` }, - cookiesRule: 'include', + companionEndpoint: 'https://companion.example.com', }); ``` :::caution `endpoint` maps to `companionEndpoint`, **not** to the new `s3Endpoint`. `s3Endpoint` is the URL of the bucket itself and is only used together with `getCredentials`. Pointing `s3Endpoint` at Companion will not work. ::: `headers` and `cookiesRule` are removed. The plugin now calls Companion with plain `fetch`, sending no custom headers and no cross-site cookies. Same-origin cookies are still sent, so a Companion served from your own origin keeps working. Bearer tokens and cross-site cookies need a new arrangement, such as an authenticating proxy in front of Companion. `getTemporarySecurityCredentials: true` (letting Companion hand out temporary credentials) is also gone. Either let Companion sign every request through `companionEndpoint`, or issue the credentials yourself with `getCredentials`. #### Temporary credentials: `getTemporarySecurityCredentials` becomes `getCredentials` **Before:** ```js uppy.use(AwsS3, { shouldUseMultipart: (file) => file.size > 100 * 2 ** 20, async getTemporarySecurityCredentials({ signal }) { const response = await fetch('/sts-token', { signal }); if (!response.ok) throw new Error('Failed to fetch STS'); // { credentials: { AccessKeyId, … }, bucket, region } return response.json(); }, }); ``` **After:** ```js uppy.use(AwsS3, { s3Endpoint: 'https://my-bucket.s3.us-east-1.amazonaws.com', region: 'us-east-1', shouldUseMultipart: (file) => file.size > 100 * 2 ** 20, async getCredentials() { const response = await fetch('/sts-token'); if (!response.ok) throw new Error('Failed to fetch STS'); const { credentials } = await response.json(); return { credentials: { accessKeyId: credentials.AccessKeyId, secretAccessKey: credentials.SecretAccessKey, sessionToken: credentials.SessionToken, expiration: credentials.Expiration, }, region: 'us-east-1', }; }, }); ``` The credential fields are camelCase now: | 5.x | 6.x | | ----------------------------- | ----------------------------- | | `credentials.AccessKeyId` | `credentials.accessKeyId` | | `credentials.SecretAccessKey` | `credentials.secretAccessKey` | | `credentials.SessionToken` | `credentials.sessionToken` | | `credentials.Expiration` | `credentials.expiration` | | `bucket` | part of the `s3Endpoint` URL | The region is no longer inferred for you. Return it from `getCredentials`; the response type requires it. At runtime the client prefers the response value, then the `region` option, then `auto`, but a callback that omits `region` does not type-check. #### Custom signing: six callbacks become `signRequest` `getUploadParameters`, `createMultipartUpload`, `listParts`, `signPart`, `abortMultipartUpload`, and `completeMultipartUpload` are replaced by a single `signRequest` function. Uppy performs the S3 API calls itself; your backend only presigns URLs. **Before:** ```js uppy.use(AwsS3, { getUploadParameters: (file) => fetchUploadParameters(file), createMultipartUpload: (file) => fetchCreateMultipartUpload(file), listParts: (file, { uploadId, key }) => fetchListParts(uploadId, key), signPart: (file, { uploadId, key, partNumber }) => fetchSignPart(uploadId, key, partNumber), abortMultipartUpload: (file, { uploadId, key }) => fetchAbort(uploadId, key), completeMultipartUpload: (file, { uploadId, key, parts }) => fetchComplete(uploadId, key, parts), }); ``` **After:** ```js uppy.use(AwsS3, { async signRequest(request) { const response = await fetch('/s3/sign', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(request), }); if (!response.ok) throw new Error('Failed to sign request'); return response.json(); // { url }, or { url, key, headers } (see below) }, }); ``` `signRequest` receives one request object and returns the presigned URL for it. Which fields are present depends on the operation: ```ts type PresignableRequest = { method: 'GET' | 'PUT' | 'POST' | 'DELETE'; key: string; uploadId?: string; partNumber?: number; expiresIn?: number; }; type PresignedResponse = { url: string; key?: string; headers?: Record; }; ``` The object key is now generated on the client (via `generateObjectKey`, by default `${crypto.randomUUID()}-${file.name}`). In 5.x the server’s key was authoritative: `getUploadParameters` returned it in `fields.key`, and `createMultipartUpload` returned it directly. In 6.x, if your server stores the object under a different key, it must tell Uppy. Return that key as `key` next to `url` in the response to the request that creates the upload (available from `@uppy/aws-s3` 6.1.0). If the server uses the key Uppy sent, leave `key` out. Change the key only on that request: every later request carries an `uploadId` and must be signed for exactly the key it arrives with, which was fixed when the upload was created. `getUploadParameters` and `signPart` could also return `headers`. Return them the same way, next to `url`, and Uppy sends them with the request (available from `@uppy/aws-s3` 6.2.0). Include only the headers that URL was signed with, such as `Content-Disposition`. The 5.x advice to always return `content-type` no longer applies: Uppy sets it from the file’s type itself. Return it only if you signed it. If your server changes the key but does not return it, a single-part upload still succeeds, but `upload-success` reports a key that does not exist in the bucket. A multipart upload only works if your server turns the same input into the same key on every request, because Uppy keeps passing the key it generated to `signRequest`. A server that generates a unique key at create time fails at the first part with `NoSuchUpload`. The [Node.js](https://github.com/transloadit/uppy/blob/main/examples/aws-nodejs/routes/presign.js) and [PHP](https://github.com/transloadit/uppy/blob/main/examples/aws-php/s3-sign.php) signer examples show how to return the key correctly. This mode needs no `s3Endpoint`: the presigned URLs you return are absolute. #### Options **Removed:** `endpoint`, `headers`, `cookiesRule`, `getTemporarySecurityCredentials`, `getUploadParameters`, `signPart`, `createMultipartUpload`, `listParts`, `abortMultipartUpload`, `completeMultipartUpload`, `uploadPartBytes`, `retryDelays`. **New:** `s3Endpoint`, `region`, `getCredentials`, `signRequest`, `companionEndpoint`, `generateObjectKey`. **Unchanged:** `shouldUseMultipart`, `limit`, `getChunkSize`, `allowedMetaFields`. ### `@uppy/instagram` removed `@uppy/instagram` and its Companion provider are removed. There is no replacement provider. **Migration steps:** 1. Remove `@uppy/instagram` from your dependencies and drop the `uppy.use(Instagram, …)` call. 2. Remove `'Instagram'` from the `sources` list if you use `@uppy/remote-sources`. Uppy 6 throws on unknown source keys. 3. Remove the Instagram credentials from your Companion configuration (`COMPANION_INSTAGRAM_KEY`, `COMPANION_INSTAGRAM_SECRET`) and the Instagram redirect URI from your provider setup. ### `@uppy/tus` no longer aborts the request on error A failed request is no longer aborted before the response is read, so the server status and body now reach the `upload-error` event and `file.response`. In 5.x the plugin emitted `upload-error` with no response argument, so consumers saw `undefined` there and `file.response` stayed unset after a failure. If you branched on that, update it: ```diff uppy.on('upload-error', (file, error, response) => { - // response was always undefined + // response.status now holds what the server sent, and + // response.body.xhr is the underlying XMLHttpRequest console.log(response?.status, response?.body?.xhr.responseText); }); ``` ### `@uppy/golden-retriever` stores metadata in IndexedDB The recovery metadata store moved from localStorage to IndexedDB, and falls back to localStorage when `window.indexedDB` is unavailable. The fallback is a one-time capability check made when the plugin starts. No code changes are needed, but recovery snapshots written by 5.x (in localStorage) are not read by 6.x, so an upload interrupted before the upgrade cannot be restored after it. ## Migrate from Companion 6.x to 7.x - OAuth tokens are sent to Uppy over the WebSocket connection instead of `window.opener.postMessage`. Upgrade Companion first: Companion 7 keeps the legacy `postMessage` fallback, so older Uppy clients keep working against it, but Uppy 6 clients do not work against Companion 6 or older. - `companion.socket()` now requires the Companion options as a second argument, the same object you pass to `companion.app()`: ```diff - companion.socket(server); + companion.socket(server, companionOptions); ``` - Companion runs on Express 5. Mounting Companion as middleware in an Express 4 app no longer works: upgrade your app to Express 5 first. - The minimum Node.js version is `^20.19.3 || >=22.0.0`. - Companion is ported to TypeScript. The port itself has no intended breaking changes, but watch for unexpected breakage. ## Migrate from Companion 5.x to 6.x - Option `companionAllowedHosts` no longer wrapped in Regex start/end characters (`^` and `$`). You now need to provide these yourself if you want an exact match. - Backwards compat token decryption removed: old Uppy auth tokens (created before [`uppy@4.16.0`](https://github.com/transloadit/uppy/releases/tag/uppy%404.16.0), commit [`06d9a7c`](https://github.com/transloadit/uppy/commit/06d9a7c689e5123d41b38191074eb8bbd4ff5325)) will become invalid, and users who have these old tokens will have to re-authenticate. - Removed `token` param from `Provider` class methods: `list()`, `download()`, `logout()`, `thumbnail()`. Please use `providerUserSession.accessToken` instead. ## Migrate from Uppy 4.x to 5.x ### @uppy/informer merged into @uppy/dashboard The `@uppy/informer` plugin has been merged into `@uppy/dashboard` to reduce bundle size and improve maintainability. The `@uppy/informer` package is no longer maintained as a standalone package and should be removed from your dependencies. ### @uppy/progress-bar deprecated The `@uppy/progress-bar` plugin has been deprecated as it provided minimal functionality that can be replicated with Uppy’s built-in state management. **Before:** ```js import ProgressBar from '@uppy/progress-bar'; uppy.use(ProgressBar, { target: '#progress' }); ``` **After:** ```js // Custom progress bar using Uppy state uppy.on('upload-progress', (file, progress) => { const progressElement = document.getElementById('progress'); progressElement.style.width = `${progress.percentage}%`; progressElement.textContent = `${progress.percentage}%`; }); // Or listen to total progress uppy.on('progress', (progress) => { const progressElement = document.getElementById('progress'); progressElement.style.width = `${progress}%`; progressElement.textContent = `${progress}%`; }); ``` **Migration steps:** 1. Remove `@uppy/progress-bar` from your dependencies 2. Create a custom progress indicator using Uppy’s `progress` or `upload-progress` events. 3. Style your progress bar according to your design system. ### @uppy/drag-drop and @uppy/file-input deprecated The `@uppy/drag-drop` and `@uppy/file-input` plugins have been deprecated in favor of more flexible, headless hooks. These hooks provide the same functionality but with maximum customization freedom. :::note Update `@uppy/drag-drop` was later restored and remains supported for setups without a JavaScript framework or build step, such as server-rendered apps (PHP, Rails, Django) using the CDN bundle or plain ` ``` Please note that while you may be able to get 2.0 to work in IE11 this way, we do not officially support it anymore. ### Use `BasePlugin` or `UIPlugin` instead of `Plugin` [`@uppy/core`][core] used to provide a `Plugin` class for creating plugins. This was used for any official plugin, but also for users who want to create their own custom plugin. But, `Plugin` always came bundled with Preact, even if the plugin itself didn’t add any UI elements. `Plugin` has been replaced with `BasePlugin` and `UIPlugin`. `BasePlugin` is the minimum you need to create a plugin and `UIPlugin` adds Preact for rendering user interfaces. You can import them from [`@uppy/core`][core]: ```js import { BasePlugin, UIPlugin } from '@uppy/core'; ``` **Note:** some bundlers will include `UIPlugin` (and thus Preact) if you import from `@uppy/core`. To make sure this does not happen, you can import `Uppy` and `BasePlugin` directly: ```js import Uppy from '@uppy/core/lib/Uppy.js'; import BasePlugin from '@uppy/core/lib/BasePlugin.js'; ``` ### Use the latest Preact for your Uppy plugins Official plugins have already been upgraded. If you are using any custom plugins, upgrade Preact to the latest version. At the time of writing this is `10.5.13`. ### Set plugin titles from locales Titles for plugins used to be set with the `title` property in the plugin options, but all other strings are set in `locale`. This has now been aligned. You should set your plugin title from the `locale` property. Before ```js import Webcam from '@uppy/webcam'; uppy.use(Webcam, { title: 'Some title', }); ``` After ```js import Webcam from '@uppy/webcam'; uppy.use(Webcam, { locale: { strings: { title: 'Some title', }, }, }); ``` ### Initialize Uppy with the `new` keyword The default export `Uppy` is no longer callable as a function. This means you construct the `Uppy` instance using the `new` keyword. ```js import Uppy from '@uppy/core'; const uppy = new Uppy(); // correct. const otherUppy = Uppy(); // incorrect, will throw. ``` ### Rename `allowMultipleUploads` to `allowMultipleUploadBatches` [`allowMultipleUploadBatches`](/docs/uppy/#allowmultipleuploadbatches) means allowing several calls to [`.upload()`](/docs/uppy/#upload), in other words, a user can add more files after already having uploaded some. We have renamed this to be more intention revealing that this is about uploads, and not whether a user can choose multiple files for one upload. ```js const uppy = new Uppy({ allowMultipleUploadBatches: true, }); ``` ### New default limits for [`@uppy/xhr-upload`][xhr] and [`@uppy/tus`][tus] The default limit has been changed from `0` to `5`. Setting this to `0` means no limit on concurrent uploads. You can change the limit on the Tus and XHR plugin options. ```js uppy.use(Tus, { // ... limit: 10, }); ``` ```js uppy.use(XHRUpload, { // ... limit: 10, }); ``` ### TypeScript changes Uppy used to have loose types by default and strict types as an opt-in. The default export was a function that returned the `Uppy` class, and the types came bundled with the default export (`Uppy.SomeType`). ```ts import Uppy from '@uppy/core'; import Tus from '@uppy/tus'; const uppy = Uppy(); uppy.use(Tus, { invalidOption: null, // this will make the compilation fail! }); ``` Uppy is now strictly typed by default and loose types have been removed. ```ts // ... const uppy = new Uppy(); uppy.use(Tus, { invalidOption: null, // this will make the compilation fail! }); ``` Uppy types are now individual exports and should be imported separately. ```ts import type { PluginOptions, UIPlugin, PluginTarget } from '@uppy/core'; ``` #### Event types [`@uppy/core`][core] provides an [`.on`](/docs/uppy/#onevent-action) method to listen to [events](/docs/uppy/#events). The types for these events were loose and allowed for invalid events to be passed, such as `uppy.on('upload-errrOOOoooOOOOOrrrr')`. ```ts // Before: type Meta = { myCustomMetadata: string }; // Invalid event uppy.on('upload-errrOOOoooOOOOOrrrr', () => { // ... }); // After: // Normal event signature uppy.on('complete', (result) => { const successResults = result.successful; }); // Custom signature type Meta = { myCustomMetadata: string }; // Notice how the custom type has now become the second argument uppy.on<'complete', Meta>('complete', (result) => { // The passed type is now merged into the `meta` types. const meta = result.successful[0].meta.myCustomMetadata; }); ``` Plugins that add their own events can merge with existing ones in `@uppy/core` with `declare module '@uppy/core' { ... }`. This is a TypeScript pattern called [module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation). For instance, when using [`@uppy/dashboard`][dashboard]: ```ts uppy.on('dashboard:file-edit-start', (file) => { const fileName = file.name; }); ``` ### Changes to pre-signing URLs for [`@uppy/aws-s3`][aws-s3] See the Uppy 2.0.0 announcement post about the batch [pre-signing URLs change](/blog/2021/08/2.0/#batch-pre-signing-urls-for-aws-s3-multipart). `prepareUploadPart` has been renamed to `signPart`. ### Removed the `.run` method from [`@uppy/core`][core] The `.run` method on the `Uppy` instance has been removed. This method was already obsolete and only logged a warning. As of this major version, it no longer exists. ### Removed `resume` and `removeFingerprintOnSuccess` options from [`@uppy/tus`][tus] Tus will now by default try to resume uploads if the upload has been started in the past. This also means tus will store some data in localStorage for each upload, which will automatically be removed on success. Making `removeFingerprintOnSuccess` obsolete too. ### That’s it! Uppy 1.0 will continue to receive bug fixes for three more months (until ), security fixes for one more year (until ), but no more new features after today. Exceptions are unlikely, but _can_ be made, to accommodate those with commercial support contracts, for example. We hope you’ll waste no time in taking Uppy 2.0 out for a walk. When you do, please let us know what you thought of it on [Reddit](https://www.reddit.com/r/javascript/comments/penbr7/uppy_file_uploader_20_smaller_and_faster_modular/), [HN](https://news.ycombinator.com/item?id=28359287), ProductHunt, or [Twitter](https://twitter.com/uppy_io/status/1432399270846603264). We’re howling at the moon to hear from you! ## Migrate from Companion 1.x to 2.x ### Prerequisite Since v2, you now need to be running `node.js >= v10.20.1` to use Companion. ### ProviderOptions In v2 the `google` and `microsoft` [providerOptions](/docs/companion/#options) have been changed to `drive` and `onedrive` respectively. ### OAuth Redirect URIs On your Providers’ respective developer platforms, the OAuth redirect URIs that you should supply has now changed from: `http(s)://$COMPANION_HOST_NAME/connect/$AUTH_PROVIDER/callback` in v1 to: `http(s)://$COMPANION_HOST_NAME/$PROVIDER_NAME/redirect` in v2 #### New Redirect URIs
| Provider | New Redirect URI | | ------------- | ---------------------------------------------------- | | Dropbox | `https://$COMPANION_HOST_NAME/dropbox/redirect` | | Google Drive | `https://$COMPANION_HOST_NAME/drive/redirect` | | Google Photos | `https://$COMPANION_HOST_NAME/googlephotos/redirect` | | OneDrive | `https://$COMPANION_HOST_NAME/onedrive/redirect` | | Box | `https://$YOUR_COMPANION_HOST_NAME/box/redirect` | | Facebook | `https://$COMPANION_HOST_NAME/facebook/redirect` | | Instagram | `https://$COMPANION_HOST_NAME/instagram/redirect` |
[core]: /docs/uppy/ [xhr]: /docs/xhr-upload/ [dashboard]: /docs/dashboard/ [aws-s3]: /docs/aws-s3/ [tus]: /docs/tus/ --- Source: https://uppy.io/docs/nextjs # Next.js Integration guide for [Next.js][] featuring the [dashboard](/docs/dashboard), the [tus](/docs/tus) uploader, [transloadit](/docs/transloadit), multipart uploads to a Next.js route, the Uppy UI components, and the [React hooks](/docs/react). :::tip Uppy also has hooks and more React examples in the [React docs](/docs/react). ::: ## Install **NPM** ```shell npm install @uppy/core @uppy/dashboard @uppy/react ``` **Yarn** ```shell yarn add @uppy/core @uppy/dashboard @uppy/react ``` ## Tus [Tus][tus] is an open protocol for resumable uploads built on HTTP. This means accidentally closing your tab or losing connection let’s you continue, for instance, your 10GB upload instead of starting all over. Tus supports any language, any platform, and any network. It requires a client and server integration to work. We will be using [tus Node.js][]. Checkout the [`@uppy/tus` docs](/docs/tus) for more information. ```tsx 'use client'; import Uppy from '@uppy/core'; // For now, if you do not want to install UI components you // are not using import from lib directly. import Dashboard from '@uppy/react/lib/Dashboard'; import Tus from '@uppy/tus'; import { useState } from 'react'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; function createUppy() { return new Uppy().use(Tus, { endpoint: '/api/upload' }); } export default function UppyDashboard() { // Important: use an initializer function to prevent the state from recreating. const [uppy] = useState(createUppy); return ; } ``` ### Pages router Attach the tus server handler to a Next.js route handler in an [optional catch-all route file](https://nextjs.org/docs/pages/building-your-application/routing/dynamic-routes#optional-catch-all-routes). `/pages/api/upload/[[...file]].ts` ```ts import type { NextApiRequest, NextApiResponse } from 'next'; import { Server, Upload } from '@tus/server'; import { FileStore } from '@tus/file-store'; /** * !Important. This will tell Next.js NOT Parse the body as tus requires * @see https://nextjs.org/docs/api-routes/request-helpers */ export const config = { api: { bodyParser: false, }, }; const tusServer = new Server({ // `path` needs to match the route declared by the next file router path: '/api/upload', datastore: new FileStore({ directory: './files' }), }); export default function handler(req: NextApiRequest, res: NextApiResponse) { return tusServer.handle(req, res); } ``` ### App router `/app/api/upload/[[...slug]]/route.ts` ```ts import { Server } from '@tus/server'; import { FileStore } from '@tus/file-store'; import { NextRequest } from 'next/server'; const server = new Server({ // `path` needs to match the route declared by the next file router // ie /api/upload path: '/api/upload', datastore: new FileStore({ directory: './files' }), }); export const GET = async (req: NextRequest) => server.handleWeb(req); export const PATCH = async (req: NextRequest) => server.handleWeb(req); export const POST = async (req: NextRequest) => server.handleWeb(req); export const DELETE = async (req: NextRequest) => server.handleWeb(req); export const OPTIONS = async (req: NextRequest) => server.handleWeb(req); export const HEAD = async (req: NextRequest) => server.handleWeb(req); ``` ## Transloadit :::tip For new integrations, use the maintained App Router example and shared security model in the canonical [Next.js + Uppy + Transloadit guide](/docs/guides/uppy-transloadit#nextjs). The manual-HMAC example below is retained only for existing integrations. ::: :::note Before continuing you should have a [Transloadit](https://transloadit.com) account and a [Template](https://transloadit.com/docs/getting-started/my-first-app/) setup. ::: Transloadit’s strength is versatility. By doing video, audio, images, documents, and more, you only need one vendor for [all your file processing needs][transloadit-services]. The [`@uppy/transloadit`](/docs/transloadit) plugin directly uploads to Transloadit so you only have to worry about creating a [template][transloadit-concepts]. It uses [Tus](#tus) under the hood so you don’t have to sacrifice reliable, resumable uploads for convenience. When you go to production always make sure to set the `signature`. **Not using [Signature Authentication](https://transloadit.com/docs/topics/signature-authentication/) can be a security risk**. Signature Authentication is a security measure that can prevent outsiders from tampering with your Assembly Instructions. Generating a signature should be done on the server to avoid leaking secrets. **App Router** `/app/api/transloadit/route.ts` ```ts import { NextResponse, NextRequest } from 'next/server'; import crypto from 'crypto'; function utcDateString(ms: number): string { return new Date(ms) .toISOString() .replace(/-/g, '/') .replace(/T/, ' ') .replace(/\.\d+Z$/, '+00:00'); } export async function POST(request: NextRequest) { // expire 1 hour from now (this must be milliseconds) const expires = utcDateString(Date.now() + 1 * 60 * 60 * 1000); const authKey = process.env.TRANSLOADIT_KEY; const authSecret = process.env.TRANSLOADIT_SECRET; const templateId = process.env.TRANSLOADIT_TEMPLATE_ID; // Typically, here you would also deny generating a signature for improper use if (!authKey || !authSecret || !templateId) { return NextResponse.json( { error: 'Missing Transloadit credentials' }, { status: 500 }, ); } const body = await request.json(); const params = JSON.stringify({ auth: { key: authKey, expires, }, template_id: templateId, fields: { // This becomes available in your Template as `${fields.customValue}` // and could be used to have a storage directory per user for example customValue: body.customValue, }, // your other params like notify_url, etc. }); const signatureBytes = crypto .createHmac('sha384', authSecret) .update(Buffer.from(params, 'utf-8')); // The final signature needs the hash name in front, so // the hashing algorithm can be updated in a backwards-compatible // way when old algorithms become insecure. const signature = `sha384:${signatureBytes.digest('hex')}`; return NextResponse.json({ expires, signature, params }); } ``` **Pages Router** `/pages/api/transloadit/params.ts` ```ts import type { NextApiRequest, NextApiResponse } from 'next'; import crypto from 'node:crypto'; function utcDateString(ms: number): string { return new Date(ms) .toISOString() .replace(/-/g, '/') .replace(/T/, ' ') .replace(/\.\d+Z$/, '+00:00'); } export default function handler(req: NextApiRequest, res: NextApiResponse) { // Typically, here you would also deny generating a signature for improper use if (req.method !== 'POST') { return res.status(405).json({ error: 'Method Not Allowed' }); } // expire 1 hour from now (this must be milliseconds) const expires = utcDateString(Date.now() + 1 * 60 * 60 * 1000); const authKey = process.env.TRANSLOADIT_KEY; const authSecret = process.env.TRANSLOADIT_SECRET; const templateId = process.env.TRANSLOADIT_TEMPLATE_ID; if (!authKey || !authSecret || !templateId) { return res.status(500).json({ error: 'Missing Transloadit credentials' }); } const params = JSON.stringify({ auth: { key: authKey, expires, }, template_id: templateId, fields: { // This becomes available in your Template as `${fields.customValue}` // and could be used to have a storage directory per user for example customValue: req.body.customValue, }, // your other params like notify_url, etc. }); const signatureBytes = crypto .createHmac('sha384', authSecret) .update(Buffer.from(params, 'utf-8')); // The final signature needs the hash name in front, so // the hashing algorithm can be updated in a backwards-compatible // way when old algorithms become insecure. const signature = `sha384:${signatureBytes.digest('hex')}`; res.status(200).json({ expires, signature, params }); } ``` On the client we want to fetch the signature and params from the server. You may want to send values from React state along to your endpoint, for instance to add [`fields`](https://transloadit.com/docs/topics/assembly-variables/) which you can use in your template as global variables. ```js // ... function createUppy() { const uppy = new Uppy(); uppy.use(Transloadit, { async assemblyOptions() { // You can send meta data along for use in your template. // https://transloadit.com/docs/topics/assembly-instructions/#form-fields-in-instructions const { meta } = uppy.getState(); const body = JSON.stringify({ customValue: meta.customValue }); const res = await fetch('/transloadit-params', { method: 'POST', body }); return response.json(); }, }); return uppy; } function Component({ customValue }) { // IMPORTANT: passing an initializer function to prevent the state from recreating. const [uppy] = useState(createUppy); useEffect(() => { if (customValue) { uppy.setOptions({ meta: { customValue } }); } }, [uppy, customValue]); } ``` ## HTTP uploads to your backend If you want to handle uploads yourself, in Next.js or another server in any language, you can use [`@uppy/xhr-upload`](/docs/xhr-upload). :::warning The server-side examples are simplified for demonstration purposes and assume a regular file upload while `@uppy/xhr-upload` can also send `FormData` through the `formData` or `bundle` options. ::: **App Router** ```ts import { NextRequest, NextResponse } from 'next/server'; import { writeFile } from 'node:fs/promises'; import path from 'node:path'; export const config = { api: { bodyParser: false, }, }; export async function POST(request: NextRequest) { const formData = await request.formData(); const file = formData.get('file') as File | null; if (!file) { return NextResponse.json({ error: 'No file uploaded' }, { status: 400 }); } const buffer = Buffer.from(await file.arrayBuffer()); const filename = file.name.replace(/\s/g, '-'); const filepath = path.join(process.cwd(), 'public', 'uploads', filename); try { await writeFile(filepath, buffer); return NextResponse.json({ message: 'File uploaded successfully', filename, }); } catch (error) { console.error('Error saving file:', error); return NextResponse.json({ error: 'Error saving file' }, { status: 500 }); } } ``` **Pages Router** ```ts import type { NextApiRequest, NextApiResponse } from 'next'; import { createWriteStream } from 'fs'; import { pipeline } from 'stream/promises'; import path from 'path'; export const config = { api: { bodyParser: false, }, }; export default async function handler( req: NextApiRequest, res: NextApiResponse, ) { if (req.method !== 'POST') { return res.status(405).json({ error: 'Method Not Allowed' }); } try { const filename = `file-${Date.now()}.txt`; const filepath = path.join(process.cwd(), 'public', 'uploads', filename); const writeStream = createWriteStream(filepath); await pipeline(req, writeStream); res.status(200).json({ message: 'File uploaded successfully', filename }); } catch (error) { console.error('Error saving file:', error); res.status(500).json({ error: 'Error saving file' }); } } ``` ```tsx 'use client'; import Uppy from '@uppy/core'; // For now, if you do not want to install UI components you // are not using import from lib directly. import Dashboard from '@uppy/react/lib/Dashboard'; import Xhr from '@uppy/xhr-upload'; import { useState } from 'react'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; function createUppy() { return new Uppy().use(Xhr, { endpoint: '/api/upload' }); } export default function UppyDashboard() { // Important: use an initializer function to prevent the state from recreating. const [uppy] = useState(createUppy); return ; } ``` ## Next steps - Add client-side file [restrictions](/docs/uppy/#restrictions). - Upload files together with other form fields with [`@uppy/form`](/docs/form). - Use your [language of choice](/docs/locales) instead of English. - Add an [image editor](/docs/image-editor) for cropping and resizing images. - Download files from remote sources, such as [Google Drive](/docs/google-drive) and [Dropbox](/docs/dropbox), with [Companion](/docs/companion). - Add [Golden Retriever](/docs/golden-retriever) to save selected files in your browser cache, so that if the browser crashes, or the user accidentally closes the tab, Uppy can restore everything and continue uploading as if nothing happened. [transloadit-concepts]: https://transloadit.com/docs/getting-started/concepts/ [transloadit-services]: https://transloadit.com/services/ [Next.js]: https://nextjs.org/ [tus]: https://tus.io/ [tus Node.js]: https://github.com/tus/tus-node-server --- Source: https://uppy.io/docs/onedrive # OneDrive The `@uppy/onedrive` plugin lets users import files from their [OneDrive](https://onedrive.com) account. :::tip [Try out the live example](/examples) or take it for a spin in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-zaqyaf?file=main.js). ::: ## When should I use this? When you want to let users import files from their [OneDrive](https://onedrive.com) account. A [Companion](/docs/companion) instance is required for the OneDrive plugin to work. Companion handles authentication with OneDrive, downloads the files, and uploads them to the destination. This saves the user bandwidth, especially helpful if they are on a mobile connection. You can self-host Companion or get a hosted version with any [Transloadit plan](https://transloadit.com/pricing/). **NPM** ```shell npm install @uppy/onedrive ``` **Yarn** ```shell yarn add @uppy/onedrive ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use Using OneDrive requires setup in both Uppy and Companion. ### Use in Uppy ```js {10-13} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import OneDrive from '@uppy/onedrive'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(OneDrive, { companionUrl: 'https://your-companion.com' }); ``` ### Use with Transloadit ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import OneDrive from '@uppy/onedrive'; uppy.use(OneDrive, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }); ``` You may also hit rate limits, because the OAuth application is shared between everyone using Transloadit. To solve that, you can use your own OAuth keys with Transloadit’s hosted Companion servers by using Transloadit Template Credentials. [Create a Template Credential][template-credentials] on the Transloadit site. Select “Companion OAuth” for the service, and enter the key and secret for the provider you want to use. Then you can pass the name of the new credentials to that provider: ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import OneDrive from '@uppy/onedrive'; uppy.use(OneDrive, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'my_companion_dropbox_creds', }, }); ``` ### Use in Companion To sign up for API keys, go to the [Azure Platform from Microsoft](https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade). Create a project for your app if you don’t have one yet. The app page has a `"Redirect URIs"` field. Here, add: ``` https://$YOUR_COMPANION_HOST_NAME/onedrive/redirect ``` If you are using Transloadit hosted Companion: ``` https://api2.transloadit.com/companion/onedrive/redirect ``` Go to the “Manifest” tab, and find the `"signInAudience"` key. Change it to `"signInAudience": "AzureADandPersonalMicrosoftAccount"`, and click “Save”. Go to the “Overview” tab. Copy the `Application (client) ID` field - this will be your Oauth client ID. Go to the “Certificates & secrets” tab, and click “+ New client secret”. Copy the `Value` field - this will be your OAuth client secret. Configure the OneDrive key and secret in Companion. With the standalone Companion server, specify environment variables: ```shell export COMPANION_ONEDRIVE_KEY="OneDrive Application ID" export COMPANION_ONEDRIVE_SECRET="OneDrive OAuth client secret value" ``` When using the Companion Node.js API, configure these options: ```js companion.app({ providerOptions: { onedrive: { key: 'OneDrive Application ID', secret: 'OneDrive OAuth client secret value', }, }, }); ``` ## API ### Options #### `id` A unique identifier for this plugin (`string`, default is a unique ID for each plugin). #### `title` Title / name shown in the UI, such as Dashboard tabs (`string`, default is the name of the plugin). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `companionUrl` URL to a [Companion](/docs/companion) instance (`string`, default: `null`). For Transloadit-hosted Companion use the `COMPANION_URL` constant exported by `@uppy/transloadit`, which is `https://api2.transloadit.com/companion`. Do not use a regional hostname such as `api2-eu-west-1.transloadit.com`: the OAuth flow then starts on one host and returns to another, and login fails with “Cannot find state in session”. #### `companionHeaders` Custom headers that should be sent along to [Companion](/docs/companion) on every request (`Object`, default: `{}`). #### `companionAllowedHosts` The valid and authorised URL(s) from which OAuth responses should be accepted (`string` or `RegExp` or `Array`). This option is useful when you have your [Companion](/docs/companion) running on several hosts. Otherwise, the default value should do fine, which uses the origin of `companionUrl`. This value can be a `string`, a `RegExp` pattern, or an `Array` of these. Strings are evaluated as regular expressions too and will be wrapped in a RegExp like so: ```js new RegExp(`^${value}$`); ``` **Important:** You must escape regex characters like `.`, or you might open your app up to security vulnerabilities. - Example correct strings - `'^(?:.*\\.)?example\.com$'` matches `example.com` and all of its subdomains. - `'https://example\.com'` matches `https://example.com` only. - Example vulnerability: `'https://www.example.com'` would allow an attacker with the domain `wwwxexample.com` to forge and inject a fraudulent token into Uppy. #### `companionKeysParams` Only applies to plugins that sign in through Companion (Google Drive, Dropbox, Box, OneDrive, …). The Google Drive Picker and Google Photos Picker ignore it; they authenticate directly with Google. Google Drive Picker uses its own `clientId`, `apiKey` and `appId`, while Google Photos Picker uses its own `clientId`. Use your own OAuth app with Transloadit-hosted Companion instead of Transloadit’s shared one (`Object`, default: `undefined`). It has two fields: - `key`: your Transloadit API key. - `credentialsName`: the name of a “Companion OAuth” credential you created in the Transloadit console, which holds the provider’s OAuth key and secret. ```js companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', } ``` Before the login popup opens, the plugin sends these values to Companion to obtain a pre-auth token, and Companion fetches the OAuth key and secret from Transloadit when the flow starts. The values are also sent along with every later request in a `uppy-credentials-params` header. Companion does not validate the credential name up front, so a wrong name only fails when a user tries to sign in. On Transloadit-hosted Companion this option is required for Google Drive, see [Google Drive: Use with Transloadit](/docs/google-drive#use-with-transloadit). #### `companionCookiesRule` This option correlates to the [RequestCredentials value](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials) (`string`, default: `'same-origin'`). This tells the plugin whether to send cookies to [Companion](/docs/companion). #### `locale` An object with `strings` property containing additional i18n strings. The key is the i18n key and the value is the English string. Example: ```js { strings: { someKey: 'Some English string', }, } ``` #### `storage` A custom storage to be used for the plugin’s persistent data. Type `AsyncStore`, default is `LocalStorage`. [template-credentials]: https://transloadit.com/docs/topics/template-credentials/ --- Source: https://uppy.io/docs/progress-bar # Progress bar ::::caution Deprecated As of Uppy 5.0, `@uppy/progress-bar` is deprecated. Use Dashboard or build a custom indicator with Uppy’s `progress`/`upload-progress` events (see examples in the [migration guide](/docs/guides/migration-guides/)). :::: `@uppy/progress-bar` is a minimalist plugin that shows the current upload progress in a thin bar element, like the ones used by YouTube and GitHub when navigating between pages. ## When should I use it? When you need a minimalistec progress indicator and you’re [building your own UI](/docs/guides/building-your-own-ui-with-uppy). For most cases, [Dashboard](/docs/dashboard) or [Drag & Drop](/docs/drag-drop) (with [Status Bar](/docs/status-bar)) is more likely what you need. ## Install **NPM** ```shell npm install @uppy/progress-bar ``` **Yarn** ```shell yarn add @uppy/progress-bar ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js import Uppy from '@uppy/core'; import ProgressBar from '@uppy/progress-bar'; import '@uppy/core/css/style.min.css'; import '@uppy/progress-bar/css/style.min.css'; new Uppy().use(ProgressBar, { target: '#progress-bar' }); ``` ## API ### Options #### `id` A unique identifier for this Progress Bar (`string`, default: `'ProgressBar'`). Use this if you need to add several ProgressBar instances. #### `target` DOM element, CSS selector, or plugin to mount the Progress Bar into (`Element`, `string`, default: `null`). #### `fixed` Show the progress bar at the top of the page with `position: fixed` (`boolean`, default: `false`). When set to false, show the progress bar inline wherever it’s mounted. #### `hideAfterFinish` Hides the progress bar after the upload has finished (`boolean`, default: `true`). --- Source: https://uppy.io/docs/react # React [React][] components for the Uppy UI plugins and hooks. ## Install **NPM** ```shell npm install @uppy/react ``` **Yarn** ```shell yarn add @uppy/react ``` :::note You may also need to install peer dependencies, for instance `@uppy/dashboard`. ::: To send files to Transloadit, follow the canonical [React + Uppy + Transloadit guide](/docs/guides/uppy-transloadit#react). It includes the required server-side signing boundary. ## Use Uppy offers three ways to build user interfaces: 1. **Pre-composed, plug-and-play components.** Mainly ``. The downside is that you can’t customize the UI. 2. **Headless components.** Smaller components, easier to override the styles or compose them together with your own components. 3. **Hooks.** Attach our logic to your own components, no restrictions, create a tailor-made UI. ### Components Pre-composed, plug-and-play components: - `` renders [`@uppy/dashboard`](/docs/dashboard) - `` renders [`@uppy/dashboard`](/docs/dashboard) as a modal - `` renders [`@uppy/status-bar`](/docs/status-bar) :::note `` and `` were removed in Uppy 5.0. Use the headless [``](#dropzone-) component or the [`useDropzone`](#usedropzoneoptions) hook instead. The [`@uppy/drag-drop`](/docs/drag-drop) plugin itself is still supported for setups without a framework. ::: ### Headless Components :::tip Play around with the React headless components in StackBlitz ::: :::note All components must be placed within a `UppyContextProvider`. ::: Uppy’s headless components are smaller and more flexible. All components must be placed within a `UppyContextProvider`. They come styled as well but you can override the styles with data attributes, for example with `UploadButton`: ```css button[data-uppy-element='upload-button'][data-state='uploading'] { background-color: lightblue; } ``` #### `UppyContextProvider` Provides Uppy context to child components and manages global upload status/progress. ```tsx import { useContext, useState } from 'react'; import { UppyContextProvider, UppyContext } from '@uppy/react'; function YourComponent() { const { uppy } = useContext(UppyContext); } export function App() { const [uppy] = useState(() => new Uppy()); return ( {/* and/or Uppy components */} ); } ``` **Context Value**: ```typescript { uppy: Uppy | undefined; status: 'init' | 'ready' | 'uploading' | 'paused' | 'error' | 'complete'; progress: number; } ``` #### `` **Attributes** - `data-uppy-element="upload-button"` - `data-state="init" | "uploading" | "paused" | "error" | "complete"` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/react for the full page.)* #### `` Component for displaying image thumbnails and/or SVG icons. **Props**: - `file: UppyFile` - `width?: string` - `height?: string` - `images?: boolean` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/react for the full page.)* #### `` Common icons, such as a webcam, device, Dropbox, Google Drive, OneDrive, etc. **Props**: - `provider`: `'device' | 'camera' | 'screen-capture' | 'audio' | 'dropbox' | 'facebook' | 'onedrive' | 'googlephotos' | 'googledrive'` - `fill?: string` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/react for the full page.)* #### `` Component for displaying a list view of selected files. **Props**: - `editFile?: (file: UppyFile) => void` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/react for the full page.)* #### `` Grid layout component for displaying files in a grid format. **Props**: - `editFile?: (file: UppyFile) => void` - `columns?: number` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/react for the full page.)* #### `` Drag-and-drop zone component for file uploads. **Props**: - `width?: string` - `height?: string` - `note?: string` - `noClick?: boolean` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/react for the full page.)* ### Hooks :::tip Play around with the React headless hooks in StackBlitz ::: :::note All hooks, except `useUppyState` and `useUppyEvent`, must be used within a `UppyContextProvider`. ::: #### `useUppyState(uppy, selector)` Use this hook when you need to access Uppy’s state reactively. ```js // IMPORTANT: passing an initializer function to prevent Uppy from being reinstantiated on every render. const [uppy] = useState(() => new Uppy()); const files = useUppyState(uppy, (state) => state.files); const totalProgress = useUppyState(uppy, (state) => state.totalProgress); // We can also get specific plugin state. // Note that the value on `plugins` depends on the `id` of the plugin. const metaFields = useUppyState( uppy, (state) => state.plugins?.Dashboard?.metaFields, ); ``` You can see all the values you can access on the [`State`](https://github.com/transloadit/uppy/blob/c45407d099d87e25cecaf03c5d9ce59c582ca0dc/packages/%40uppy/core/src/Uppy.ts#L155-L181) type. If you are accessing plugin state, you would have to look at the types of the plugin. #### `useUppyEvent(uppy, event, callback)` Listen to Uppy events in a React component. The first item in the array is an array of results from the event. Depending on the event, that can be empty or have up to three values. The second item is a function to clear the results. Values remain in state until the next event (if that ever comes). Depending on your use case, you may want to keep the values in state or clear the state after something else happenend. ```ts // IMPORTANT: passing an initializer function to prevent Uppy from being reinstantiated on every render. const [uppy] = useState(() => new Uppy()); const [results, clearResults] = useUppyEvent(uppy, 'transloadit:result'); const [stepName, result, assembly] = results; // strongly typed useUppyEvent(uppy, 'cancel-all', clearResults); ``` #### `useDropzone(options?)` Creates a dropzone for drag-and-drop file uploads using Uppy. **Arguments**: - `noClick?: boolean` - `onDragOver?: (event: Event) => void` - `onDragEnter?: (event: Event) => void` - `onDragLeave?: (event: Event) => void` - `onDrop?: (files: File[]) => void` - `onFileInputChange?: (files: File[]) => void` **Returns**: - `getRootProps: Function` - `getInputProps: Function` #### `useFileInput(props?)` Creates a file input for programmatic file selection using Uppy. **Arguments**: - `multiple?: boolean` - `accept?: string` **Returns**: - `getInputProps: Function` - `getButtonProps: Function` #### `useRemoteSource(sourceId)` Manages remote source connections (cloud storage providers). **Arguments**: - `sourceId: 'Box' | 'Dropbox' | 'Facebook' | 'GoogleDrive' | 'OneDrive' | 'Unsplash' | 'Url' | 'Zoom'` **Returns**: ```typescript { state: { authenticated: boolean | undefined didFirstRender: boolean searchString: string loading: boolean | string partialTree: PartialTree currentFolderId: PartialTreeId username: string | null breadcrumbs: PartialTreeFolder[] selectedAmount: number error: string | null } login: Function logout: Function open: Function checkbox: Function done: Function cancel: Function } ``` #### `useWebcam({ onSubmit })` Manages webcam functionality for capturing photos/videos. **Arguments**: - `onSubmit: () => void` **Returns**: ```typescript { state: { hasCamera: boolean cameraReady: boolean cameraError: null | Error recordingLengthSeconds: number videoSources: MediaDeviceInfo[] currentDeviceId: string | MediaStreamTrack | null | undefined recordedVideo: null | string isRecording: boolean status: 'init' | 'ready' | 'recording' | 'captured' | 'error' } stop: Function start: Function getVideoProps: Function getSnapshotButtonProps: Function getRecordButtonProps: Function getStopRecordingButtonProps: Function getSubmitButtonProps: Function getDiscardButtonProps: Function } ``` #### `useScreenCapture({ onSubmit })` Manages screen capture functionality for capturing screen image / video. **Arguments**: - `onSubmit: () => void` **Returns**: ```typescript { state: { streamActive: boolean; audioStreamActive: boolean; recording: boolean; recordedVideo: string | null; screenRecError: Error | null; capturedScreenshotUrl: string | null; status: 'init' | 'ready' | 'recording' | 'captured' | 'error'; } stop: Function; start: Function; getVideoProps: Function; getScreenshotButtonProps: Function; getRecordButtonProps: Function; getStopRecordingButtonProps: Function; getSubmitButtonProps: Function; getDiscardButtonProps: Function; } ``` ## Examples ### Example: basic component Here we have a basic component which ties Uppy’s state to the component. This means you can render multiple instances. But be aware that as your component unmounts, for instance because the user navigates to a different page, Uppy’s state will be lost and uploads will stop. :::note If you render multiple instances of Uppy, make sure to give each instance a unique `id`. ::: ```js import React, { useEffect, useState } from 'react'; import Uppy from '@uppy/core'; import Webcam from '@uppy/webcam'; import Dashboard from '@uppy/react/dashboard'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; import '@uppy/webcam/css/style.min.css'; function Component() { // IMPORTANT: passing an initializer function to prevent Uppy from being reinstantiated on every render. const [uppy] = useState(() => new Uppy().use(Webcam)); return ; } ``` ### Example: keep Uppy state and uploads while navigating between pages When you want Uppy’s state to persist and keep uploads running between pages, you can [lift the state up](https://react.dev/learn/sharing-state-between-components#lifting-state-up-by-example). ```js import React, { useState, useEffect } from 'react'; import Uppy from '@uppy/core'; import Dashboard from '@uppy/react/dashboard'; function Page1() { // ... } function Page2({ uppy }) { return ( <>

{totalProgress}

); } export default function App() { // keeping the uppy instance alive above the pages the user can switch during uploading const [uppy] = useState(() => new Uppy()); return ( // Add your router here <> ); } ``` ### Example: updating Uppy’s options dynamically based on props ```js // ... function Component(props) { // IMPORTANT: passing an initializer function to prevent the state from recreating. const [uppy] = useState(() => new Uppy().use(Webcam)); useEffect(() => { uppy.setOptions({ restrictions: props.restrictions }); }, [props.restrictions]); useEffect(() => { uppy.getPlugin('Webcam').setOptions({ modes: props.webcamModes }); }, [props.webcamModes]); return ; } ``` ### Example: dynamic params and signature for Transloadit When you go to production always make sure to set the `signature`. **Not using [Signature Authentication](https://transloadit.com/docs/topics/signature-authentication/) can be a security risk**. Signature Authentication is a security measure that can prevent outsiders from tampering with your Assembly Instructions. Generating a signature should be done on the server to avoid leaking secrets. In React, this could get awkward with a `fetch` in a `useEffect` and setting it to `useState`. Instead, it’s easier to use the [`assemblyOptions`](/docs/transloadit#assemblyoptions) option to `fetch` the params. ```js // ... function createUppy() { const uppy = new Uppy(); uppy.use(Transloadit, { async assemblyOptions() { // You can send meta data along for use in your template. // https://transloadit.com/docs/topics/assembly-instructions/#form-fields-in-instructions const { meta } = uppy.getState(); const body = JSON.stringify({ userId: meta.userId }); const res = await fetch('/transloadit-params', { method: 'POST', body }); return res.json(); }, }); return uppy; } function Component({ userId }) { // IMPORTANT: passing an initializer function to prevent Uppy from being reinstantiated on every render. const [uppy] = useState(createUppy); useEffect(() => { if (userId) { // Adding to global `meta` will add it to every file. uppy.setOptions({ meta: { userId } }); } }, [uppy, userId]); } ``` [react]: https://facebook.github.io/react --- Source: https://uppy.io/docs/reactrouter # React Router Integration guide for the [React][] components for the Uppy UI plugins and hooks. :::tip Uppy also has hooks and more React examples in the [React docs](/docs/react). ::: ## Install ```shell npm install @uppy/core @uppy/dashboard @uppy/react ``` ## Tus [Tus][tus] is an open protocol for resumable uploads built on HTTP. This means accidentally closing your tab or losing connection lets you continue, for instance, your 10GB upload instead of starting all over. Tus supports any language, any platform, and any network. It requires a client and server integration to work. We will be using [tus Node.js][]. Checkout the [`@uppy/tus` docs](/docs/tus) for more information. Create a route where you want to handle uploads: ```tsx import { useEffect, useState } from 'react'; import Uppy from '@uppy/core'; import Dashboard from '@uppy/react/lib/Dashboard'; import Tus from '@uppy/tus'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; function createUppy() { return new Uppy().use(Tus, { endpoint: '/api/upload' }); } export default function UppyDashboard() { // Important: use an initializer function to prevent the state from recreating. const [uppy] = useState(createUppy); return ; } ``` [`@tus/server`][tus Node.js] does not support react router resource routes yet, which is based on the fetch `Request` API instead of `http.IncomingMessage` and `http.ServerResponse`. However we can workaround it by using a custom server, which is a common pattern with React Router. The [docs](https://remix.run/docs/en/main/other-api/adapter) for this are still on the Remix site, but the same packages exist under the `@react-router/*` scope. The exact code to integrate [tus Node.js][] in your custom server depends on the framework you choose. Head over to the `@tus/server` [examples for the most popular Node.js servers](https://github.com/tus/tus-node-server/tree/main/packages/server#examples) to find the one that works for you. ## Transloadit :::note Before continuing you should have a [Transloadit](https://transloadit.com) account and a [template](https://transloadit.com/docs/getting-started/my-first-app/) setup. ::: Transloadit’s strength is versatility. By doing video, audio, images, documents, and more, you only need one vendor for [all your file processing needs][transloadit-services]. The [`@uppy/transloadit`](/docs/transloadit) plugin directly uploads to Transloadit so you only have to worry about creating a [template][transloadit-concepts]. It uses [Tus](#tus) under the hood so you don’t have to sacrifice reliable, resumable uploads for convenience. When you go to production always make sure to set the `signature`. **Not using [Signature Authentication](https://transloadit.com/docs/topics/signature-authentication/) can be a security risk**. Signature Authentication is a security measure that can prevent outsiders from tampering with your Assembly Instructions. Generating a signature should be done on the server to avoid leaking secrets. Start by creating a [resource route](https://reactrouter.com/how-to/resource-routes) to generate the signature and params: ```ts import { data } from 'react-router'; import type { ActionFunction } from 'react-router'; import crypto from 'crypto'; function utcDateString(ms: number): string { return new Date(ms) .toISOString() .replace(/-/g, '/') .replace(/T/, ' ') .replace(/\.\d+Z$/, '+00:00'); } export const action: ActionFunction = async ({ request }) => { // expire 1 hour from now (this must be milliseconds) const expires = utcDateString(Date.now() + 1 * 60 * 60 * 1000); const authKey = process.env.TRANSLOADIT_KEY; const authSecret = process.env.TRANSLOADIT_SECRET; const templateId = process.env.TRANSLOADIT_TEMPLATE_ID; if (!authKey || !authSecret || !templateId) { throw data({ error: 'Missing Transloadit credentials' }, { status: 500 }); } const body = await request.json(); const params = JSON.stringify({ auth: { key: authKey, expires, }, template_id: templateId, fields: { // You can use this in your template. customValue: body.customValue, }, // your other params like notify_url, etc. }); const signatureBytes = crypto .createHmac('sha384', authSecret) .update(Buffer.from(params, 'utf-8')); // The final signature needs the hash name in front, so // the hashing algorithm can be updated in a backwards-compatible // way when old algorithms become insecure. const signature = `sha384:${signatureBytes.digest('hex')}`; return data({ expires, signature, params }); }; ``` On the client we want to fetch the signature and params from the server. You may want to send values from React state along to your endpoint, for instance to add [`fields`](https://transloadit.com/docs/topics/assembly-variables/) which you can use in your template as global variables. ```js // app/routes/upload-transloadit.tsx import { Transloadit } from '@uppy/transloadit'; function createUppy() { const uppy = new Uppy(); uppy.use(Transloadit, { async assemblyOptions() { // You can send meta data along for use in your template. // https://transloadit.com/docs/topics/assembly-instructions/#form-fields-in-instructions const { meta } = uppy.getState(); const body = JSON.stringify({ customValue: meta.customValue }); const res = await fetch('/transloadit-params', { method: 'POST', body, }); return res.json(); }, }); return uppy; } function Component({ customValue }) { // IMPORTANT: passing an initializer function to prevent the state from recreating. const [uppy] = useState(createUppy); useEffect(() => { if (customValue) { uppy.setOptions({ meta: { customValue } }); } }, [uppy, customValue]); } ``` ## HTTP uploads to your backend If you want to handle uploads yourself, you can use [`@uppy/xhr-upload`](/docs/xhr-upload). Create a [resource route](https://reactrouter.com/how-to/resource-routes), such as `app/routes/upload/route.ts`: ```ts import { LocalFileStorage } from '@mjackson/file-storage/local'; import { type FileUpload, parseFormData } from '@mjackson/form-data-parser'; import { type ActionFunctionArgs } from 'react-router'; const fileStorage = new LocalFileStorage('./uploads'); export async function action({ request }: ActionFunctionArgs) { const user = requireUser(request); // your optional logic const uploadHandler = async (fileUpload: FileUpload) => { const storageKey = `user-${user.id}-avatar`; await fileStorage.set(storageKey, fileUpload); return fileStorage.get(storageKey); }; const formData = await parseFormData(request, uploadHandler); for (const [key, value] of formData.entries()) { console.log(key, value); } return Response.json(null); } ``` Create a page with your Uppy instance: ```tsx import Uppy from '@uppy/core'; import Dashboard from '@uppy/react/lib/Dashboard'; import Xhr from '@uppy/xhr-upload'; import { useState } from 'react'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; function createUppy() { return new Uppy().use(Xhr, { endpoint: '/upload' }); } export default function UppyDashboard() { // Important: use an initializer function to prevent the state from recreating. const [uppy] = useState(createUppy); return ; } ``` If you want to send along other form fields with your upload, you can use [`@uppy/form`](/docs/form). ```tsx {4,20-23,26-30} import Uppy from '@uppy/core'; import Dashboard from '@uppy/react/lib/Dashboard'; import Xhr from '@uppy/xhr-upload'; import Form from '@uppy/form'; import { useEffect, useState } from 'react'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; function createUppy() { return new Uppy().use(Xhr, { endpoint: '/upload' }); } export default function UppyDashboard() { // Important: use an initializer function to prevent the state from recreating. const [uppy] = useState(createUppy); // @uppy/form is client-side only so we need to install it // when the component is mounted. useEffect(() => { uppy.use(Form, { target: '#form' }); return () => uppy.removePlugin(uppy.getPlugin('Form')!); }, [uppy]); return ( ; ); } ``` ## Next steps - Add client-side file [restrictions](/docs/uppy/#restrictions). - Upload files together with other form fields with [`@uppy/form`](/docs/form). - Use your [language of choice](/docs/locales) instead of English. - Add an [image editor](/docs/image-editor) for cropping and resizing images. - Download files from remote sources, such as [Google Drive](/docs/google-drive) and [Dropbox](/docs/dropbox), with [Companion](/docs/companion). - Add [Golden Retriever](/docs/golden-retriever) to save selected files in your browser cache, so that if the browser crashes, or the user accidentally closes the tab, Uppy can restore everything and continue uploading as if nothing happened. [transloadit-concepts]: https://transloadit.com/docs/getting-started/concepts/ [transloadit-services]: https://transloadit.com/services/ [react]: https://facebook.github.io/react [tus]: https://tus.io/ [tus Node.js]: https://github.com/tus/tus-node-server --- Source: https://uppy.io/docs/remote-sources # Remote sources `@uppy/remote-sources` is a preset plugin (meaning it bundles and sets up other plugins) to add all the available remote sources, such as Google Drive, Dropbox, and others to Uppy Dashboard in one package. :::note Remote Sources requires Dashboard and automatically installs all its plugins to it. ::: ## When should I use it? `@uppy/remote-sources` aims to simplify the setup for adding Companion plugins, when you want to share the configuration between plugins. If you want your users to upload files from any of the remote sources that Uppy offers, this plugin is recommended. A [Companion](/docs/companion) instance is required for the Remote Sources plugin to work. Companion handles authentication with the remote services (such as Facebook, Dropbox, etc.), downloads the files, and uploads them to the destination. This saves the user bandwidth, especially helpful if they are on a mobile connection. You can self-host Companion or get a hosted version with any [Transloadit plan](https://transloadit.com/pricing/). ## Install **NPM** ```shell npm install @uppy/remote-sources ``` **Yarn** ```shell yarn add @uppy/remote-sources ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js {10} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import RemoteSources from '@uppy/remote-sources'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy(); .use(Dashboard); .use(RemoteSources, { companionUrl: 'https://your-companion-url' }); ``` ### Use with Transloadit ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import RemoteSources from '@uppy/remote-sources'; uppy.use(RemoteSources, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }); ``` :::warning Google Drive needs your own Google OAuth app Transloadit’s shared Google OAuth app is blocked by Google, so the Google Drive plugin does not work on Transloadit-hosted Companion with the default credentials. Users get a Google page that says “This app is blocked”. To use this plugin with hosted Companion you have to register your own Google OAuth app and hand it to Companion as a Transloadit credential, see [Use with Transloadit](/docs/google-drive#use-with-transloadit). The [Google Drive Picker](/docs/google-drive-picker) plugin uses the non-restricted `drive.file` scope, so it needs no Google verification, but it still needs your own Google Cloud client ID, API key and app ID. Background: [Navigating Google’s API changes](https://transloadit.com/blog/2025/02/the-new-google-situation/). ::: You may also hit rate limits, because the OAuth application is shared between everyone using Transloadit. To use your own OAuth keys with Transloadit’s hosted Companion servers, [create a credential][template-credentials] on the Transloadit site (the console calls them Third-party Credentials). Select “Companion OAuth” for the service, pick the provider, and enter the key and secret. Then pass the name of the credential to the matching plugin, keyed by plugin ID, together with your Transloadit API key. The [Google Drive page](/docs/google-drive#use-with-transloadit) has the full setup for Google. ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import RemoteSources from '@uppy/remote-sources'; uppy.use(RemoteSources, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, companionKeysParams: { GoogleDrive: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', }, Dropbox: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'dropbox_own', }, // ...etc }, }); ``` ## API ### Options #### `id` A unique identifier for this plugin (`string`, default: `RemoteSources`). #### `sources` List of remote sources that will be enabled (`array`, default: `['Box', 'Dropbox', 'Facebook', 'GoogleDrive', 'OneDrive', 'Unsplash', 'Url', 'Zoom']`). You don’t need to specify them manually or change them, but if you want to alter the order in which they appear in the Dashboard, or disable some sources, this option is for you. ```js uppy.use(RemoteSources, { companionUrl: 'https://your-companion-url', sources: ['Dropbox', 'GoogleDrive', 'Unsplash', 'Url'], }); ``` #### `companionUrl` URL to a [Companion](/docs/companion) instance (`string`, default: `null`). #### `companionHeaders` Custom headers that should be sent along to [Companion](/docs/companion) on every request (`object`, default: `{}`). #### `companionAllowedHosts` The valid and authorized URL(s)/URL pattern(s) from which OAuth responses should be accepted (`string | RegExp | Array`, Default: `companionUrl`). This value can be a `string`, a `RegExp` object, or an array of both. This is useful when you have your [Companion](/docs/companion) running on several hosts. Otherwise, the default value, which is `companionUrl`, should do fine. #### `companionCookiesRule` This option correlates to the [`Request.credentials` value][], which tells the plugin whether to send cookies to [Companion](/docs/companion) (`string`, default: `same-origin`). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). [`request.credentials` value]: https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials [template-credentials]: https://transloadit.com/docs/topics/template-credentials/ --- Source: https://uppy.io/docs/screen-capture # Screen capture The `@uppy/screen-capture` plugin can record your screen or an application and save it as a video. :::tip [Try out the live example](/examples) or take it for a spin in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-zaqyaf?file=main.js). ::: ## When should I use this? When you want users record their screen on their computer. This plugin only works on desktop browsers which support [`getDisplayMedia API`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia). If no support for the API is detected, Screen Capture won’t be installed, so you don’t have to do anything. :::note To use the screen capture plugin in a Chromium-based browser, [your site must be served over https](https://developers.google.com/web/updates/2015/10/chrome-47-webrtc#public_service_announcements). This restriction does not apply on `localhost`, so you don’t have to jump through many hoops during development. ::: ## Install **NPM** ```shell npm install @uppy/screen-capture ``` **Yarn** ```shell yarn add @uppy/screen-capture ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js {3,7,11} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import ScreenCapture from '@uppy/screen-capture'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; import '@uppy/screen-capture/css/style.min.css'; new Uppy().use(Dashboard, { inline: true, target: 'body' }).use(ScreenCapture); ``` ### API ### Options #### `id` A unique identifier for this plugin (`string`, default: `'ScreenCapture'`). #### `title` Configures the title / name shown in the UI, for instance, on Dashboard tabs (`string`, default: `'Screen Capture'`). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `displayMediaConstraints` Options passed to [`MediaDevices.getDisplayMedia()`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) (`Object`, default: `null`). See the [`MediaTrackConstraints`](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints) for a list of options. #### `userMediaConstraints` Options passed to [`MediaDevices.getUserMedia()`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia) (`Object`, default: `null`). See the [`MediaTrackConstraints`](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints) for a list of options. #### `preferredVideoMimeType` Set the preferred mime type for video recordings, for example `'video/webm'` (`string`, default: `null`). If the browser supports the given mime type, the video will be recorded in this format. If the browser does not support it, it will use the browser default. If no preferred video mime type is given, the ScreenCapture plugin will prefer types listed in the [`allowedFileTypes` restriction](/docs/uppy/#restrictions), if any. #### `locale` ```js export default { strings: { startCapturing: 'Begin screen capturing', stopCapturing: 'Stop screen capturing', submitRecordedFile: 'Submit recorded file', streamActive: 'Stream active', streamPassive: 'Stream passive', micDisabled: 'Microphone access denied by user', recording: 'Recording', }, }; ``` --- Source: https://uppy.io/docs/status-bar # Status bar The `@uppy/status-bar` plugin shows upload progress and speed, estimated time, pre- and post-processing information, and allows users to control (pause/resume/cancel) the upload. :::tip Try it out together with [`@uppy/drag-drop`](/docs/drag-drop) in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-yzbujq?file=main.js/g) ::: ## When should I use it? When you use the [Dashboard](/docs/dashboard) it’s already included by default. This plugin is published separately but made specifically for the Dashboard. You can still use it without it but it may need some (CSS) tweaking for your use case. ## Install **NPM** ```shell npm install @uppy/status-bar ``` **Yarn** ```shell yarn add @uppy/status-bar ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use ```js showLineNumbers import Uppy from '@uppy/core'; import StatusBar from '@uppy/status-bar'; import '@uppy/core/css/style.min.css'; import '@uppy/status-bar/css/style.min.css'; new Uppy().use(StatusBar, { target: '#status-bar' }); ``` ## API ### Options #### `id` A unique identifier for this Status Bar (`string`, default: `'StatusBar'`). Use this if you need to add several StatusBar instances. #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `hideAfterFinish` Hide the Status Bar after the upload is complete (`boolean`, default: `true`). #### `showProgressDetails` Display remaining upload size and estimated time (`boolean`, default: `false`) :::note `false`: Uploading: 45% `true`: Uploading: 45%・43 MB of 101 MB・8s left ::: #### `hideUploadButton` Hide the upload button (`boolean`, default: `false`). Use this if you are providing a custom upload button somewhere, and using the `uppy.upload()` API. #### `hideRetryButton` Hide the retry button (`boolean`, default: `false`). Use this if you are providing a custom retry button somewhere, and using the `uppy.retryAll()` or `uppy.retryUpload(fileID)` API. #### `hidePauseResumeButton` Hide pause/resume buttons (for resumable uploads, via [tus](http://tus.io), for example) (`boolean`, default: `false`). Use this if you are providing custom cancel or pause/resume buttons somewhere, and using the `uppy.pauseResume(fileID)` or `uppy.removeFile(fileID)` API. #### `hideCancelButton` Hide the cancel button (`boolean`, default: `false`). Use this if you are providing a custom retry button somewhere, and using the `uppy.cancelAll()` API. #### `doneButtonHandler` Status Bar will render a “Done” button in place of pause/resume/cancel buttons, once the upload/encoding is done (`Function`, default: `null`). The behaviour of this “Done” button is defined by the handler function — can be used to close file picker modals or clear the upload state. This is what the Dashboard plugin, which uses Status Bar internally, sets: ```js const doneButtonHandler = () => { this.uppy.reset(); this.requestCloseModal(); }; ``` #### `locale` ```js export default { strings: { // Shown in the status bar while files are being uploaded. uploading: 'Uploading', // Shown in the status bar once all files have been uploaded. complete: 'Complete', // Shown in the status bar if an upload failed. uploadFailed: 'Upload failed', // Shown in the status bar while the upload is paused. paused: 'Paused', // Used as the label for the button that retries an upload. retry: 'Retry', // Used as the label for the button that cancels an upload. cancel: 'Cancel', // Used as the label for the button that pauses an upload. pause: 'Pause', // Used as the label for the button that resumes an upload. resume: 'Resume', // Used as the label for the button that resets the upload state after an upload done: 'Done', // When `showProgressDetails` is set, shows the number of files that have been fully uploaded so far. filesUploadedOfTotal: { 0: '%{complete} of %{smart_count} file uploaded', 1: '%{complete} of %{smart_count} files uploaded', }, // When `showProgressDetails` is set, shows the amount of bytes that have been uploaded so far. dataUploadedOfTotal: '%{complete} of %{total}', // When `showProgressDetails` is set, shows an estimation of how long the upload will take to complete. xTimeLeft: '%{time} left', // Used as the label for the button that starts an upload. uploadXFiles: { 0: 'Upload %{smart_count} file', 1: 'Upload %{smart_count} files', }, // Used as the label for the button that starts an upload, if another upload has been started in the past // and new files were added later. uploadXNewFiles: { 0: 'Upload +%{smart_count} file', 1: 'Upload +%{smart_count} files', }, upload: 'Upload', retryUpload: 'Retry upload', xMoreFilesAdded: { 0: '%{smart_count} more file added', 1: '%{smart_count} more files added', }, showErrorDetails: 'Show error details', }, }; ``` --- Source: https://uppy.io/docs/guides/browser-support # Supporting IE11 We officially support recent versions of Chrome, Firefox, Safari and Edge. Internet Explorer is not officially supported, as in we don’t run tests for it, but you can be mostly confident it works with the right polyfills. But it does come with a risk of unexpected results in styling or functionality. ## Polyfills **NPM** ```shell npm install core-js whatwg-fetch abortcontroller-polyfill md-gum-polyfill resize-observer-polyfill ``` **Yarn** ```shell yarn add core-js whatwg-fetch abortcontroller-polyfill md-gum-polyfill resize-observer-polyfill ``` ```js import 'core-js'; import 'whatwg-fetch'; import 'abortcontroller-polyfill/dist/polyfill-patch-fetch'; // Order matters: AbortController needs fetch which needs Promise (provided by core-js). import 'md-gum-polyfill'; import ResizeObserver from 'resize-observer-polyfill'; window.ResizeObserver ??= ResizeObserver; export { default } from '@uppy/core'; export * from '@uppy/core'; ``` --- Source: https://uppy.io/docs/svelte # Svelte [Svelte][] components for the Uppy UI plugins. ## Install **NPM** ```shell npm install @uppy/svelte ``` **Yarn** ```shell yarn add @uppy/svelte ``` :::note You also need to install the UI plugin you want to use. For instance, `@uppy/dashboard`. ::: ## Use Uppy offers three ways to build user interfaces: 1. **Pre-composed, plug-and-play components.** Mainly ``. The downside is that you can’t customize the UI. 2. **Headless components** (Svelte 5 only). Smaller components, easier to override the styles or compose them together with your own components. 3. **Hooks** (Svelte 5 only). Attach our logic to your own components, no restrictions, create a tailor-made UI. ### Components Pre-composed, plug-and-play components: - `` renders [`@uppy/dashboard`](/docs/dashboard) - `` renders [`@uppy/dashboard`](/docs/dashboard) as a modal - `` renders [`@uppy/status-bar`](/docs/status-bar) :::note `` and `` were removed in Uppy 5.0. Use the headless [``](#dropzone-) component or the [`useDropzone`](#usedropzoneoptions) hook instead (Svelte 5 only). The [`@uppy/drag-drop`](/docs/drag-drop) plugin itself is still supported for setups without a framework. ::: ### Headless Components :::tip Play around with the Svelte headless components in StackBlitz ::: :::note All components must be placed within a `UppyContextProvider`. Headless components only work with Svelte 5 ::: Uppy’s headless components are smaller and more flexible. All components must be placed within a `UppyContextProvider`. They come styled as well but you can override the styles with data attributes, for example with `UploadButton`: ```css button[data-uppy-element='upload-button'][data-state='uploading'] { background-color: lightblue; } ``` #### `UppyContextProvider` Provides Uppy context to child components and manages global upload status/progress. ```svelte ``` **Context Value**: ```typescript { uppy: Uppy | undefined; status: 'init' | 'ready' | 'uploading' | 'paused' | 'error' | 'complete'; progress: number; } ``` #### `` **Attributes** - `data-uppy-element="upload-button"` - `data-state="init" | "uploading" | "paused" | "error" | "complete"` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/svelte for the full page.)* #### `` Component for displaying image thumbnails and/or SVG icons. **Props**: - `file: UppyFile` - `width?: string` - `height?: string` - `images?: boolean` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/svelte for the full page.)* #### `` Common icons, such as a webcam, device, Dropbox, Google Drive, OneDrive, etc. **Props**: - `provider`: `'device' | 'camera' | 'screen-capture' | 'audio' | 'dropbox' | 'facebook' | 'onedrive' | 'googlephotos' | 'googledrive'` - `fill?: string` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/svelte for the full page.)* #### `` Component for displaying a list view of selected files. **Props**: - `editFile?: (file: UppyFile) => void` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/svelte for the full page.)* #### `` Grid layout component for displaying files in a grid format. **Props**: - `editFile?: (file: UppyFile) => void` - `columns?: number` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/svelte for the full page.)* #### `` Drag-and-drop zone component for file uploads. **Props**: - `width?: string` - `height?: string` - `note?: string` - `noClick?: boolean` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/svelte for the full page.)* ### Hooks :::tip Play around with the Svelte headless hooks in StackBlitz ::: :::note All hooks must be used within a `UppyContextProvider`. Hooks only work in Svelte 5. ::: #### `useDropzone(options?)` Creates a dropzone for drag-and-drop file uploads using Uppy. **Arguments**: - `noClick?: boolean` - `onDragOver?: (event: Event) => void` - `onDragEnter?: (event: Event) => void` - `onDragLeave?: (event: Event) => void` - `onDrop?: (files: File[]) => void` - `onFileInputChange?: (files: File[]) => void` **Returns**: - `getRootProps: Function` - `getInputProps: Function` #### `useFileInput(props?)` Creates a file input for programmatic file selection using Uppy. **Arguments**: - `multiple?: boolean` - `accept?: string` **Returns**: - `getInputProps: Function` - `getButtonProps: Function` #### `useRemoteSource(sourceId)` Manages remote source connections (cloud storage providers). **Arguments**: - `sourceId: 'Box' | 'Dropbox' | 'Facebook' | 'GoogleDrive' | 'OneDrive' | 'Unsplash' | 'Url' | 'Zoom'` **Returns**: ```typescript { state: { authenticated: boolean | undefined didFirstRender: boolean searchString: string loading: boolean | string partialTree: PartialTree currentFolderId: PartialTreeId username: string | null breadcrumbs: PartialTreeFolder[] selectedAmount: number error: string | null } login: Function logout: Function open: Function checkbox: Function done: Function cancel: Function } ``` #### `useWebcam({ onSubmit })` Manages webcam functionality for capturing photos/videos. **Arguments**: - `onSubmit: () => void` **Returns**: ```typescript { state: { hasCamera: boolean cameraReady: boolean cameraError: null | Error recordingLengthSeconds: number videoSources: MediaDeviceInfo[] currentDeviceId: string | MediaStreamTrack | null | undefined recordedVideo: null | string isRecording: boolean status: 'init' | 'ready' | 'recording' | 'captured' | 'error' } stop: Function start: Function getVideoProps: Function getSnapshotButtonProps: Function getRecordButtonProps: Function getStopRecordingButtonProps: Function getSubmitButtonProps: Function getDiscardButtonProps: Function } ``` #### `useScreenCapture({ onSubmit })` Manages screen capture functionality for capturing screen image / video. **Arguments**: - `onSubmit: () => void` **Returns**: ```typescript { state: { streamActive: boolean; audioStreamActive: boolean; recording: boolean; recordedVideo: string | null; screenRecError: Error | null; capturedScreenshotUrl: string | null; status: 'init' | 'ready' | 'recording' | 'captured' | 'error'; } stop: Function; start: Function; getVideoProps: Function; getScreenshotButtonProps: Function; getRecordButtonProps: Function; getStopRecordingButtonProps: Function; getSubmitButtonProps: Function; getDiscardButtonProps: Function; } ``` [svelte]: https://svelte.dev --- Source: https://uppy.io/docs/sveltekit # SvelteKit Integration guide for using Uppy UI plugins and components with SvelteKit. :::tip Uppy can be used with any JavaScript framework. This guide shows how to integrate Uppy with SvelteKit. ::: ## Install ```shell npm install @uppy/core @uppy/dashboard @uppy/svelte ``` ## Tus [Tus][tus] is an open protocol for resumable uploads built on HTTP. This means accidentally closing your tab or losing connection lets you continue, for instance, your 10GB upload instead of starting all over. Tus supports any language, any platform, and any network. It requires a client and server integration to work. We will be using [tus Node.js][]. Check out the [`@uppy/tus` docs](/docs/tus) for more information. Create a route where you want to handle uploads: ```svelte ``` [`@tus/server`][tus Node.js] does not directly support SvelteKit endpoints, which use the Fetch API’s `Request` and `Response` objects. However, you can integrate `@tus/server` by setting up a [custom server](https://svelte.dev/docs/kit/adapter-node#Custom-server). SvelteKit supports multiple [adapters](https://kit.svelte.dev/docs/adapters), so choose the one that fits your needs. The exact code to integrate [tus Node.js][] in your custom server depends on the framework you choose. Head over to the `@tus/server` [examples for the most popular Node.js servers](https://github.com/tus/tus-node-server/tree/main/packages/server#examples) to find the one that works for you. ## Transloadit :::note Before continuing, you should have a [Transloadit](https://transloadit.com) account and a [template](https://transloadit.com/docs/getting-started/my-first-app/) set up. ::: Transloadit’s strength is versatility. By handling video, audio, images, documents, and more, you only need one vendor for [all your file processing needs][transloadit-services]. The [`@uppy/transloadit`](/docs/transloadit) plugin directly uploads to Transloadit, so you only have to worry about creating a [template][transloadit-concepts]. It uses [Tus](#tus) under the hood, so you don’t have to sacrifice reliable, resumable uploads for convenience. When you go to production, always make sure to set the `signature`. **Not using [Signature Authentication](https://transloadit.com/docs/topics/signature-authentication/) can be a security risk**. Signature Authentication is a security measure that can prevent outsiders from tampering with your Assembly Instructions. Generating a signature should be done on the server to avoid leaking secrets. Start by creating a [server route](https://svelte.dev/docs/kit/routing#server) to generate the signature and params: ```ts // src/routes/transloadit-params/+server.ts import type { RequestHandler } from '@sveltejs/kit'; import crypto from 'crypto'; function utcDateString(ms: number): string { return new Date(ms) .toISOString() .replace(/-/g, '/') .replace(/T/, ' ') .replace(/\.\d+Z$/, '+00:00'); } export const POST: RequestHandler = async ({ request }) => { // Expire 1 hour from now (this must be milliseconds) const expires = utcDateString(Date.now() + 1 * 60 * 60 * 1000); const authKey = process.env.TRANSLOADIT_KEY; const authSecret = process.env.TRANSLOADIT_SECRET; const templateId = process.env.TRANSLOADIT_TEMPLATE_ID; if (!authKey || !authSecret || !templateId) { return new Response( JSON.stringify({ error: 'Missing Transloadit credentials' }), { status: 500 }, ); } const body = await request.json(); const params = JSON.stringify({ auth: { key: authKey, expires, }, template_id: templateId, fields: { // You can use this in your template. customValue: body.customValue, }, // Your other params like notify_url, etc. }); const signatureBytes = crypto .createHmac('sha384', authSecret) .update(Buffer.from(params, 'utf-8')); // The final signature needs the hash name in front, so // the hashing algorithm can be updated in a backwards-compatible // way when old algorithms become insecure. const signature = `sha384:${signatureBytes.digest('hex')}`; return new Response(JSON.stringify({ expires, signature, params }), { headers: { 'Content-Type': 'application/json' }, }); }; ``` On the client, we want to fetch the signature and params from the server. You may want to send values from Svelte state along to your endpoint, for instance, to add [`fields`](https://transloadit.com/docs/topics/assembly-variables/) which you can use in your template as global variables. ```svelte ``` ## HTTP uploads to your backend If you want to handle uploads yourself, you can use [`@uppy/xhr-upload`](/docs/xhr-upload). Create an endpoint, such as `src/routes/upload/+server.ts`: ```ts import type { RequestHandler } from '@sveltejs/kit'; import { requireUser } from '$lib/auth'; // Your optional logic import fs from 'fs'; import path from 'path'; export const POST: RequestHandler = async ({ request }) => { const user = await requireUser(request); // Your optional logic const formData = await request.formData(); const files = formData.getAll('files[]'); // Assuming 'files[]' is the field name used for (const file of files) { if (file instanceof File) { const arrayBuffer = await file.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); const storageKey = `user-${user.id}-avatar-${file.name}`; const uploadPath = path.join('uploads', storageKey); fs.writeFileSync(uploadPath, buffer); console.log(`Saved file to ${uploadPath}`); } } return new Response(null); }; ``` Create a page with your Uppy instance: ```svelte ``` If you want to send along other form fields with your upload, you can use [`@uppy/form`](/docs/form). ```svelte
``` ## Next steps - Add client-side file [restrictions](/docs/uppy/#restrictions). - Upload files together with other form fields with [`@uppy/form`](/docs/form). - Use your [language of choice](/docs/locales) instead of English. - Add an [image editor](/docs/image-editor) for cropping and resizing images. - Download files from remote sources, such as [Google Drive](/docs/google-drive) and [Dropbox](/docs/dropbox), with [Companion](/docs/companion). - Add [Golden Retriever](/docs/golden-retriever) to save selected files in your browser cache, so that if the browser crashes, or the user accidentally closes the tab, Uppy can restore everything and continue uploading as if nothing happened. [transloadit-concepts]: https://transloadit.com/docs/getting-started/concepts/ [transloadit-services]: https://transloadit.com/services/ [tus]: https://tus.io/ [tus Node.js]: https://github.com/tus/tus-node-server --- Source: https://uppy.io/docs/thumbnail-generator # Thumbnail generator `@uppy/thumbnail-generator` generates proportional thumbnails (file previews) for images that are added to Uppy. ## When should I use this? This plugin is included by default with the [Dashboard](/docs/dashboard) plugin, and can also be useful to display image previews in a custom UI. :::note Thumbnails are only generated for _local_ files. Remote files through [Companion](/docs/companion) generally won’t have thumbnails because they are downloaded on the server. Some providers, such as Google Drive, have baked in thumbnails into their API responses. ::: ## Install **NPM** ```shell npm install @uppy/thumbnail-generator ``` **Yarn** ```shell yarn add @uppy/thumbnail-generator ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use If you use the [Dashboard](/docs/dashboard) then it’s already installed. If you want to use it programmatically for your own UI: ```js showLineNumbers import Uppy from '@uppy/core'; import ThumbnailGenerator from '@uppy/thumbnail-generator'; const uppy = new Uppy(); uppy.use(ThumbnailGenerator); uppy.on('thumbnail:generated', (file, preview) => doSomething(file, preview)); ``` ## API ### Options #### `id` A unique identifier for this plugin (`string`, default: `'ThumbnailGenerator'`). #### `locale` ```js export default { strings: { generatingThumbnails: 'Generating thumbnails...', }, }; ``` #### `thumbnailWidth` Width of the resulting thumbnail (`number`, default: `200`). Thumbnails are always proportional and not cropped. If width is provided, height is calculated automatically to match ratio. If both width and height are given, only width is taken into account. #### `thumbnailHeight` Height of the resulting thumbnail (`number`, default: `200`). Thumbnails are always proportional and not cropped. If height is provided, width is calculated automatically to match ratio. If both width and height are given, only width is taken into account. :::note Produce a 300px height thumbnail with calculated width to match ratio: ```js uppy.use(ThumbnailGenerator, { thumbnailHeight: 300 }); ``` Produce a 300px width thumbnail with calculated height to match ratio (and ignore the given height): ```js uppy.use(ThumbnailGenerator, { thumbnailWidth: 300, thumbnailHeight: 300 }); ``` See issue [#979](https://github.com/transloadit/uppy/issues/979) and [#1096](https://github.com/transloadit/uppy/pull/1096) for details on this feature. ::: #### `thumbnailType` MIME type of the resulting thumbnail (`string`, default: `'image/jpeg'`). This is useful if you want to support transparency in your thumbnails by switching to `image/png`. #### `waitForThumbnailsBeforeUpload` Whether to wait for all thumbnails to be ready before starting the upload (`boolean`, default: `false`). If set to `true`, Thumbnail Generator will invoke Uppy’s internal processing stage and wait for `thumbnail:all-generated` event, before proceeding to the uploading stage. This is useful because Thumbnail Generator also adds EXIF data to images, and if we wait until it’s done processing, this data will be available on the server after the upload. ### Events :::info You can use [`on`](/docs/uppy#onevent-action) and [`once`](/docs/uppy#onceevent-action) to listen to these events. ::: #### `thumbnail:generated` Emitted with `file` and `preview` local url as arguments: ```js uppy.on('thumbnail:generated', (file, preview) => { const img = document.createElement('img'); img.src = preview; img.width = 100; document.body.appendChild(img); }); ``` --- Source: https://uppy.io/docs/transloadit # Transloadit The `@uppy/transloadit` plugin can be used to upload files directly to [Transloadit](https://transloadit.com/) for all kinds of processing, such as transcoding video, resizing images, zipping/unzipping, [and much more][transloadit-services]. :::tip Canonical framework guide Follow [Use Uppy with Transloadit](/docs/guides/uppy-transloadit) for complete, signed examples in JavaScript, React, Next.js, Vue, and Angular. Uppy owns the open-source upload experience; Transloadit owns the managed processing backend. ::: ## When should I use it? :::tip Not sure which uploader is best for you? Read “[Choosing the uploader you need](/docs/guides/choosing-uploader)”. ::: Transloadit’s strength is versatility. By doing video, audio, images, documents, and more, you only need one vendor for [all your file processing needs][transloadit-services]. The `@uppy/transloadit` plugin directly uploads to Transloadit so you don’t have to worry about setting up and maintaining your own servers, all you have to do is create a [Template][transloadit-concepts] that describes what should happen to the uploaded files. Transloadit accepts the files, processes according to the instructions in the Template, and stores the results in storage of your choosing, such as a self-owned S3 bucket. The Transloadit plugin uses [Tus](/docs/tus) under the hood so you don’t have to sacrifice reliable, resumable uploads. You should use `@uppy/transloadit` if you don’t want to host your own Tus or Companion servers, (optionally) need file processing, and store it in the service (such as S3 or GCS) of your liking. All with minimal effort. ## Install **NPM** ```shell npm install @uppy/transloadit ``` **Yarn** ```shell yarn add @uppy/transloadit ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use A quick overview of the complete API. ```js {10-17} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import Transloadit from '@uppy/transloadit'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; const uppy = new Uppy() .use(Dashboard, { inline: true, target: 'body' }) .use(Transloadit, { assemblyOptions: { params: { auth: { key: 'your-transloadit-key' }, template_id: 'your-template-id', }, }, }); // Optionally listen to events uppy.on('transloadit:assembly-created', (assembly, fileIDs) => {}); uppy.on('transloadit:upload', (file, assembly) => {}); uppy.on('transloadit:assembly-executing', (assembly) => {}); uppy.on('transloadit:result', (stepName, result, assembly) => {}); uppy.on('transloadit:complete', (assembly) => {}); ``` ### Use with Companion :::note All [Transloadit plans](https://transloadit.com/pricing/) come with a hosted version of Companion. ::: You can use this plugin together with Transloadit’s hosted Companion service to let your users import files from third party sources across the web. To do so each provider plugin must be configured with Transloadit’s Companion URLs: ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Dropbox from '@uppy/dropbox'; uppy.use(Dropbox, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }); ``` This already works for most providers. Transloadit’s OAuth applications are used to authenticate your users by default. Your users will be asked to provide Transloadit access to their files. Since your users are probably not aware of Transloadit, this may be confusing or decrease trust. You may also hit rate limits, because the OAuth application is shared between everyone using Transloadit. :::warning Google Drive needs your own Google OAuth app Transloadit’s shared Google OAuth app is blocked by Google, so the Google Drive plugin does not work on Transloadit-hosted Companion with the default credentials. Users get a Google page that says “This app is blocked”. To use this plugin with hosted Companion you have to register your own Google OAuth app and hand it to Companion as a Transloadit credential, see [Use with Transloadit](/docs/google-drive#use-with-transloadit). The [Google Drive Picker](/docs/google-drive-picker) plugin uses the non-restricted `drive.file` scope, so it needs no Google verification, but it still needs your own Google Cloud client ID, API key and app ID. Background: [Navigating Google’s API changes](https://transloadit.com/blog/2025/02/the-new-google-situation/). ::: To use your own OAuth keys with Transloadit’s hosted Companion servers, [create a credential][template-credentials] on the Transloadit site (the console calls them Third-party Credentials). Select “Companion OAuth” for the service, pick the provider, and enter the key and secret. Then pass the name of the credential to that provider plugin together with your Transloadit API key: ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Dropbox from '@uppy/dropbox'; uppy.use(Dropbox, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'my_companion_dropbox_creds', }, }); ``` ## API ### Options #### `id` A unique identifier for this plugin (`string`, default: `'Transloadit'`). #### `service` The Transloadit API URL to use (`string`, default: `https://api2.transloadit.com`). The default will try to route traffic efficiently based on the location of your users. You could for instance set it to `https://api2-us-east-1.transloadit.com` if you need the traffic to stay inside a particular region. #### `limit` Limit the amount of uploads going on at the same time (`number`, default: `20`). Setting this to `0` means no limit on concurrent uploads, but we recommend a value between `5` and `20`. This option is passed through to the [`@uppy/tus`](/docs/tus) plugin, which this plugin uses internally. #### `assemblyOptions` Configure the [Assembly Instructions](https://transloadit.com/docs/topics/assembly-instructions/), the fields to send along to the assembly, and authentication (`object | function`, default: `null`). The object you can pass or return from a function has this structure: ```js { params: { auth: { key: 'key-from-transloadit' }, template_id: 'id-from-transloadit', steps: { // Overruling Template at runtime }, notify_url: 'https://your-domain.com/assembly-status', }, signature: 'generated-signature', fields: { // Dynamic or static fields to send along }, } ``` - `params` is used to authenticate with Transloadit and using your desired [template](https://transloadit.com/docs/topics/templates/). - `auth.key` _(required)_ is your authentication key which you can find on the “Credentials” page of your account. - `template_id` _(required)_ is the unique identifier to use the right template from your account. - `steps` _(optional)_ can be used to [overrule Templates at runtime](https://transloadit.com/docs/topics/templates/#overruling-templates-at-runtime). A typical use case might be changing the storage path on the fly based on the session user id. For most use cases, we recommend to let your Templates handle dynamic cases (they can accept `fields` and execute arbitrary JavaScript as well), and not pass in `steps` from a browser. The template editor also has extra validations and context. - `notify_url` _(optional)_ is a pingback with the assembly status as JSON. For instance, if you don’t want to block the user experience by letting them wait for your template to complete with [`waitForEncoding`](#waitforencoding), but you do want to want to asynchrounously have an update, you can provide an URL which will be “pinged” with the assembly status. - `signature` _(optional, but recommended)_ is a cryptographic signature to provide further trust in unstrusted environments. Refer to “[Signature Authentication”](https://transloadit.com/docs/topics/signature-authentication/) for more information. - `fields` _(optional)_ can be used to to send along key/value pairs, which can be [used dynamically in your template](https://transloadit.com/docs/topics/assembly-instructions/#form-fields-in-instructions). :::info All your files end up in a single assembly and your `fields` are available globally in your template. The metadata in your Uppy files is also sent along so you can do things dynamically per file with `file.user_meta` in your template. :::
Examples **As a function** Most likely you want to use a function to call your backend to generate a signature and return your configuration. ```js uppy.use(Transloadit, { async assemblyOptions() { const res = await fetch('/transloadit-params'); return res.json(); }, }); ``` **As an object** If you don’t need to change anything dynamically, you can also pass an object directly. ```js uppy.use(Transloadit, { assemblyOptions: { params: { auth: { key: 'transloadit-key' } }, }, }); ``` **Use with @uppy/form** Combine the `assemblyOptions()` option with the [Form](/docs/form) plugin to pass user input from a `
` to a Transloadit Assembly: ```js // This will add form field values to each file's `.meta` object: uppy.use(Form, { getMetaFromForm: true }); uppy.use(Transloadit, { async assemblyOptions() { const res = await fetch('/transloadit-params'); return res.json(); }; }); ```
:::caution When you go to production always make sure to set the `signature`. **Not using [Signature Authentication](https://transloadit.com/docs/topics/signature-authentication/) can be a security risk**. Signature Authentication is a security measure that can prevent outsiders from tampering with your Assembly Instructions. While Signature Authentication is not implemented (yet), we recommend to disable `allow_steps_override` in your Templates to avoid outsiders being able to pass in any Instructions and storage targets on your behalf. ::: #### `waitForEncoding` Wait for the template to finish, rather than only the upload, before marking the upload complete (`boolean`, default: `false`). - When `false`, the Assemblies will complete (or error) in the background but Uppy won’t know or care about it. You may have to let Transloadit ping you via a `notify_url` and asynchronously inform your user (email, in-app notification). - When `true`, the Transloadit plugin waits for Assemblies to complete before the files are marked as completed. This means users have to wait for a potentially long time, depending on how complicated your Assembly instructions are. But, you can receive the final status and transcoding results on the client side with less effort. When this is enabled, you can listen for the [`transloadit:result`](#transloaditresult) and [`transloadit:complete`](#transloaditcomplete) events. #### `waitForMetadata` Wait for Transloadit’s backend to catch early errors, not the entire Assembly to complete. (`boolean`, default: `false`) When set to `true`, the Transloadit plugin waits for Transloadit’s backend to extract metadata from all the uploaded files. This is mostly handy if you want to have a quick user experience (so your users don’t necessarily need to wait for all the encoding to complete), but you do want to let users know about some types of errors that can be caught early on, like file format issues. You you can listen for the [`transloadit:upload`](#transloaditupload) event when this or `waitForEncoding` is enabled. #### `importFromUploadURLs` Allow another plugin to upload files, and then import those files into the Transloadit Assembly (`boolean`, default: `false`). When enabling this option, Transloadit will _not_ configure the Tus plugin to upload to Transloadit. Instead, a separate upload plugin must be used. Once the upload completes, the Transloadit plugin adds the uploaded file to the Assembly. For example, to upload files to an S3 bucket and then transcode them: ```js uppy.use(AwsS3, { getUploadParameters(file) { return { /* upload parameters */ }; }, }); uppy.use(Transloadit, { importFromUploadURLs: true, assemblyOptions: { params: { auth: { key: 'YOUR_API_KEY' }, template_id: 'YOUR_TEMPLATE_ID', }, }, }); ``` Tranloadit will download the files and expose them to your Template as `:original`, as if they were directly uploaded from the Uppy client. :::note For this to work, the upload plugin must assign a publicly accessible `uploadURL` property to the uploaded file object. The Tus and S3 plugins both do this automatically, but you must configure your S3 bucket to have publicly readable objects. For the XHRUpload plugin, you may have to specify a custom `getResponseData` function. ::: #### `alwaysRunAssembly` Always create and run an Assembly when `uppy.upload()` is called, even if no files were selected (`boolean`, default: `false`). This allows running Assemblies that do not receive files, but instead use a robot like [`/s3/import`](https://transloadit.com/docs/transcoding/#s3-import) to download the files from elsewhere, for example, for a bulk transcoding job. #### `locale` ```js export default { strings: { // Shown while Assemblies are being created for an upload. creatingAssembly: 'Preparing upload...', // Shown if an Assembly could not be created. creatingAssemblyFailed: 'Transloadit: Could not create Assembly', // Shown after uploads have succeeded, but when the Assembly is still executing. // This only shows if `waitForMetadata` or `waitForEncoding` was enabled. encoding: 'Encoding...', }, }; ``` #### `clientName` Append a custom client name to the `Transloadit-Client` header field when creating an Assembly (`string`, default: `null`). The `Transloadit-Client` header includes by default information about the used SDK and is included in the Assembly Status under the `transloadit_client` property. By providing a value, such as `homepage-file-uploader`, you can identify the client and SDK that created a given Assembly.
Deprecated options These options have been deprecated in favor of [`assemblyOptions`](#assemblyoptions), which we now recommend for all use cases. You can still use these options, but they will be removed in the next major version. #### `getAssemblyOptions` This function behaves the same as passing a function to [`assemblyOptions`](#assemblyoptions). #### `params` The Assembly parameters to use for the upload (`object`, default: `null`) See the Transloadit documentation on [Assembly Instructions](https://transloadit.com/docs/#14-assembly-instructions) for further information. The `auth.key` Assembly parameter is required. You can also use the `steps` or `template_id` options here as described in the Transloadit documentation. ```js uppy.use(Transloadit, { params: { auth: { key: 'YOUR_TRANSLOADIT_KEY' }, steps: { encode: { robot: '/video/encode', use: { steps: [':original'], fields: ['file_input_field2'], }, preset: 'iphone', }, }, }, }); ``` #### `signature` An optional signature for the Assembly parameters. See the Transloadit documentation on [Signature Authentication](https://transloadit.com/docs/#26-signature-authentication) for further information. If a `signature` is provided, `params` should be a JSON string instead of a JavaScript object, as otherwise the generated JSON in the browser may be different from the JSON string that was used to generate the signature. #### `fields` An object of form fields to send along to the Assembly. Keys are field names, and values are field values. See also the Transloadit documentation on [Form Fields In Instructions](https://transloadit.com/docs/#23-form-fields-in-instructions). ```js uppy.use(Transloadit, { // ... fields: { message: 'This is a form field', }, }); ``` You can also pass an array of field names to send global or file metadata along to the Assembly. Global metadata is set using the [`meta` option](/docs/uppy/#meta) in the Uppy constructor, or using the [`setMeta` method](/docs/uppy/#setmetadata). File metadata is set using the [`setFileMeta`](/docs/uppy/#setfilemetafileid-data) method. The [Form](/docs/form) plugin also sets global metadata based on the values of ``s in the form, providing a handy way to use values from HTML form fields: ```js uppy.use(Form, { target: 'form#upload-form', getMetaFromForm: true }); uppy.use(Transloadit, { fields: ['field_name', 'other_field_name'], params: { /* ... */ }, }); ``` Form fields can also be computed dynamically using custom logic, by using the [`getAssemblyOptions(file)`](/docs/transloadit/#getassemblyoptions) option.
### Plugin state The plugin mirrors the Assembly Status into its own plugin state, so you can render Assembly progress without wiring up event listeners. Read it with [`getPluginState()`](/docs/uppy/#getpluginstate), or from Uppy’s state under `plugins.Transloadit` (the key is the plugin [`id`](#id)). ```js const { assemblyStatus, lastAssemblyStatus } = uppy .getPlugin('Transloadit') .getPluginState(); ``` #### `assemblyStatus` The [Assembly Status][assembly-status] of the Assembly that is currently running (`object | undefined`, default: `undefined`). It is updated on every status transition Transloadit reports (such as `ASSEMBLY_UPLOADING` and then `ASSEMBLY_EXECUTING` in the `ok` property), and is set back to `undefined` as soon as there is no live Assembly, which is the case after the upload finished, was cancelled, or errored. #### `lastAssemblyStatus` The most recent [Assembly Status][assembly-status] that was seen (`object | undefined`, default: `undefined`). This one is never cleared, so it stays readable after [`assemblyStatus`](#assemblystatus) goes back to `undefined`, and is overwritten when the next Assembly reports a status. It is the last status the plugin _observed_, not necessarily the final outcome: with the default [`waitForEncoding: false`](#waitforencoding), the plugin stops following the Assembly once the upload is done, so the stored status can still say `ASSEMBLY_UPLOADING` or `ASSEMBLY_EXECUTING` while Transloadit finishes the job server-side. ### Static exports #### `COMPANION_URL` The main endpoint for Transloadit’s hosted companions. You can use this constant in remote provider options, like so: ```js import Dropbox from '@uppy/dropbox'; import { COMPANION_URL } from '@uppy/transloadit'; uppy.use(Dropbox, { companionUrl: COMPANION_URL, }); ``` When using `COMPANION_URL`, you should also configure [`companionAllowedHosts`](#companion_allowed_hosts). The value of this constant is `https://api2.transloadit.com/companion`. If you are using a custom [`service`](#service) option, you should also set a custom host option in your provider plugins, by taking a Transloadit API url and appending `/companion`: ```js uppy.use(Dropbox, { companionUrl: 'https://api2-us-east-1.transloadit.com/companion', }); ``` #### `COMPANION_ALLOWED_HOSTS` A RegExp pattern matching Transloadit’s hosted companion endpoints. The pattern is used in remote provider `companionAllowedHosts` options, to make sure that third party authentication messages cannot be faked by an attacker’s page but can only originate from Transloadit’s servers. Use it whenever you use `companionUrl: COMPANION_URL`, like so: ```js import Dropbox from '@uppy/dropbox'; import { COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; uppy.use(Dropbox, { companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }); ``` The value of this constant covers _all_ Transloadit’s Companion servers, so it does not need to be changed if you are using a custom [`service`](#service) option. But, if you are not using the Transloadit Companion servers at `*.transloadit.com`, make sure to set the `companionAllowedHosts` option to something that matches what you do use. ### Events #### `transloadit:assembly-created` Fired when an Assembly is created. **Parameters** - `assembly` - The initial [Assembly Status][assembly-status]. - `fileIDs` - The IDs of the files that will be uploaded to this Assembly. ```js uppy.on('transloadit:assembly-created', (assembly, fileIDs) => { console.group('Created', assembly.assembly_id, 'for files:'); for (const id of fileIDs) { console.log(uppy.getFile(id).name); } console.groupEnd(); }); ``` #### `transloadit:upload` Fired when Transloadit has received an upload. Requires [`waitForMetadata`](#waitformetadata) to be set. **Parameters** - `file` - The Transloadit file object that was uploaded. - `assembly` - The [Assembly Status][assembly-status] of the Assembly to which the file was uploaded. #### `transloadit:assembly-executing` Fired when Transloadit has received all uploads, and is executing the Assembly. **Parameters** - `assembly` - The [Assembly Status](https://transloadit.com/docs/api/#assembly-status-response) of the Assembly that is executing. #### `transloadit:result` Fired when a result came in from an Assembly. Requires [`waitForEncoding`](#waitforencoding) to be set. **Parameters** - `stepName` - The name of the Assembly step that generated this result. - `result` - The result object from Transloadit. This result object has one more property, namely `localId`. This is the ID of the file in Uppy’s local state, and can be used with `uppy.getFile(id)`. - `assembly` - The [Assembly Status][assembly-status] of the Assembly that generated this result. ```js uppy.on('transloadit:result', (stepName, result) => { const file = uppy.getFile(result.localId); document.body.appendChild(html`

From ${file.name}

View
`); }); ``` #### `transloadit:complete` Fired when an Assembly completed. Requires [`waitForEncoding`](#waitforencoding) to be set. **Parameters** - `assembly` - The final [Assembly Status][assembly-status] of the completed Assembly. ```js uppy.on('transloadit:complete', (assembly) => { // Could do something fun with this! console.log(assembly.results); }); ``` ## Frequently Asked Questions ### Accessing the assembly when an error occurred If an error occurs when an Assembly has already started, you can find the Assembly Status on the error object’s `assembly` property. ```js uppy.on('error', (error) => { if (error.assembly) { console.log(`Assembly ID ${error.assembly.assembly_id} failed!`); console.log(error.assembly); } }); ``` ### Assembly behavior when Uppy is closed When integrating `@uppy/transloadit` with `@uppy/dashboard`, closing the dashboard will result in continuing assemblies on the server. When the user manually cancels the upload any running assemblies will be cancelled. [assembly-status]: https://transloadit.com/docs/api/#assembly-status-response [template-credentials]: https://transloadit.com/docs/topics/template-credentials/ [transloadit-services]: https://transloadit.com/services/ [transloadit-concepts]: https://transloadit.com/docs/getting-started/concepts/ --- Source: https://uppy.io/docs/tus # Tus The `@uppy/tus` plugin brings resumable file uploading with [Tus](http://tus.io) to Uppy by wrapping the [`tus-js-client`][]. ## When should I use it? :::tip Not sure which uploader is best for you? Read “[Choosing the uploader you need](/docs/guides/choosing-uploader)”. ::: [Tus][tus] is an open protocol for resumable uploads built on HTTP. This means accidentally closing your tab or losing connection let’s you continue, for instance, your 10GB upload instead of starting all over. Tus supports any language, any platform, and any network. It requires a client and server integration to work. You can checkout the client and server [implementations][] to find the server in your preferred language. You can store files on the Tus server itself, but you can also use service integrations (such as S3) to store files externally. If you don’t want to host your own server, see “[Are there hosted Tus servers?](#are-there-hosted-tus-servers)”. If you want reliable, resumable uploads: use `@uppy/tus` to connect to your Tus server in a few lines of code. ## Install **NPM** ```shell npm install @uppy/tus ``` **Yarn** ```shell yarn add @uppy/tus ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use A quick overview of the complete API. ```js {10} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import Tus from '@uppy/tus'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: 'body' }) .use(Tus, { endpoint: 'https://tusd.tusdemo.net/files/' }); ``` ### TypeScript If you want the `response` argument on the `upload-success` event and `file.response.body` to be typed, you have to pass a generic to the Uppy class. ```ts showLineNumbers // ... import Tus, { type TusBody } from '@uppy/tus'; type MyMeta = { /* your added meta data */ }; const uppy = new Uppy().use(Tus, { endpoint: 'https://tusd.tusdemo.net/files/', }); const [firstFile] = uppy.getFiles(); // Correctly typed as XMLHttpRequest. // Populated after uppy.upload() firstFile.response.body.xhr; ``` ## API ### Options :::info All options are passed to `tus-js-client` and we document the ones here that are required, added, or changed. This means you can also pass functions like [`onAfterResponse`](https://github.com/tus/tus-js-client/blob/master/docs/api.md#onafterresponse). We recommended taking a look at the [API reference](https://github.com/tus/tus-js-client/blob/master/docs/api.md) from `tus-js-client` to know what is supported. ::: #### `id` A unique identifier for this plugin (`string`, default: `'Tus'`). #### `endpoint` URL of the tus server (`string`, default: `null`). #### `headers` An object or function returning an object with HTTP headers to send along requests (`object | function`, default: `null`). Keys are header names, values are header values. ```js const headers = { authorization: `Bearer ${window.getCurrentUserToken()}`, }; ``` Header values can also be derived from file data by providing a function. The function receives an [Uppy file][] and must return an object where the keys are header names, and values are header values. ```js const headers = (file) => { return { authorization: `Bearer ${window.getCurrentUserToken()}`, expires: file.meta.expires, }; }; ``` #### `chunkSize` A number indicating the maximum size of a `PATCH` request body in bytes (`number`, default: `Infinity`). Note that this option only affects local browser uploads. If you need a max chunk size for remote (Companion) uploads, you must set the `chunkSize` Companion option as well. :::caution Do not set this value unless you are forced to. The two valid reasons are described in the [`tus-js-client` docs](https://github.com/tus/tus-js-client/blob/master/docs/api.md#chunksize). ::: #### `withCredentials` Configure the requests to send Cookies using the [`xhr.withCredentials`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials) property (`boolean`, default: `false`). The remote server must accept CORS and credentials. #### `retryDelays` When uploading a chunk fails, automatically try again after the defined millisecond intervals (`Array`, default: `[0, 1000, 3000, 5000]`). By default, we first retry instantly; if that fails, we retry after 1 second; if that fails, we retry after 3 seconds, etc. Set to `null` to disable automatic retries, and fail instantly if any chunk fails to upload. #### `onBeforeRequest(req, file)` Behaves like the [`onBeforeRequest`](https://github.com/tus/tus-js-client/blob/master/docs/api.md#onbeforerequest) function from `tus-js-client` but with the added `file` argument. #### `onShouldRetry: (err, retryAttempt, options, next)` When an upload fails `onShouldRetry` is called with the error and the default retry logic as the last argument (`function`). The default retry logic is an [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) algorithm triggered on HTTP 429 (Too Many Requests) errors. Meaning if your server (or proxy) returns HTTP 429 because it’s being overloaded, @uppy/tus will find the ideal sweet spot to keep uploading without overloading. If you want to extend this functionality, for instance to retry on unauthorized requests (to retrieve a new authentication token): ```js import Uppy from '@uppy/core'; import Tus from '@uppy/tus'; new Uppy().use(Tus, { endpoint: '', async onBeforeRequest(req) { const token = await getAuthToken(); req.setHeader('Authorization', `Bearer ${token}`); }, onShouldRetry(err, retryAttempt, options, next) { if (err?.originalResponse?.getStatus() === 401) { return true; } return next(err); }, async onAfterResponse(req, res) { if (res.getStatus() === 401) { await refreshAuthToken(); } }, }); ``` #### `allowedMetaFields` Pass an array of field names to limit the metadata fields that will be added to uploads as [Tus Metadata](https://tus.io/protocols/resumable-upload.html#upload-metadata) (`Array`, default: `null`). - Set it to `false` to not send any fields (or an empty array). - Set it to `['name']` to only send the `name` field. - Set it to `true` (the default) to send _all_ metadata fields. #### `limit` Limit the amount of uploads going on at the same time (`number`, default: `20`). Setting this to `0` means no limit on concurrent uploads (not recommended). ### Errors When a request fails and the [retries](#retrydelays) are exhausted, the server’s response is forwarded to the [`upload-error`](/docs/uppy/#upload-error) event and set on `file.response`: the `status` the server returned, and a `body` holding the underlying `xhr`. ```js uppy.on('upload-error', (file, error, response) => { console.log(response?.status); // for instance 403 console.log(response?.body.xhr.responseText); // what the server sent back }); ``` Before Uppy 6.0 the plugin aborted the request in its error handler and emitted `upload-error` without a response at all, so this third argument was always `undefined` and `file.response` was never set on a failed upload. `response` is `undefined` when there is no server response to report: when the request failed without one (such as an unreachable server; use [`error.isNetworkError`](/docs/uppy/#upload-error) to detect those), and for remote files uploaded through Companion, which report errors without a response object. ## Frequently Asked Questions :::info The Tus website has extensive [FAQ section](https://tus.io/faq.html), we recommend taking a look there as well if something is unclear. ::: ### How is file meta data stored? Tus uses unique identifiers for the file names to prevent naming collisions. To still keep the meta data in place, Tus also uploads an extra `.info` file with the original file name and other meta data: ```json { "ID": "00007a99d16d4eeb5a3e3c080b6f69da+JHZavdqPSK4VMtarg2yYcNiP8t_kDjN51lBYMJdEyr_wqEotVl8ZBRBSTnWKWenZBwHvbLNz5tQXYp2N7Vdol.04ysQAuw__suTJ4IsCljj0rjyWA6LvV4IwF5P2oom2", "Size": 1679852, "SizeIsDeferred": false, "Offset": 0, "MetaData": { "filename": "cat.jpg", "filetype": "image/jpeg" }, "IsPartial": false, "IsFinal": false, "PartialUploads": null, "Storage": { "Bucket": "your-bucket", "Key": "some-key", "Type": "s3store" } } ``` ### How do I change files before sending them? If you want to change the file names, you want to do that in [`onBeforeFileAdded`](/docs/uppy/#onbeforefileaddedfile-files). If you want to send extra headers with the request, use [`headers`](#headers) or [`onBeforeRequest`](#onbeforerequestreq-file). ### How do I change (or move) files after sending them? If you want to preserve files names, extract meta data, or move files to a different place you generally can with hooks or events. It depends on the Tus server you use how it’s done exactly. [`tusd`][], for instance, exposes [hooks](https://github.com/tus/tusd/blob/master/docs/hooks.md) and [`tus-node-server`](https://github.com/tus/tus-node-server) has [events](https://github.com/tus/tus-node-server#events). ### Which server do you recommend? [Transloadit](https://transloadit.com) runs [`tusd`][] in production, where it serves millions of requests globally. So we recommend `tusd` as battle-tested from our side, but other companies have had success with other [implementations][] so it depends on your needs. ### Are there hosted Tus servers? All [Transloadit plans](https://transloadit.com/pricing) come with a hosted [`tusd`][] server. You don’t have to do anything to leverage it, using [`@uppy/transloadit`](/docs/transloadit) automatically uses Tus under the hood. ### Why Tus instead of directly uploading to AWS S3? First: reliable, resumable uploads. This means accidentally closing your tab or losing connection let’s you continue, for instance, your 10GB upload instead of starting all over. Tus is also efficient with lots of files (such as 8K) and large files. Uploading to AWS S3 directly from the client also introduces quite a bit of overhead, as more requests are needed for the flow to work. [`tus-js-client`]: https://github.com/tus/tus-js-client [uppy file]: /docs/uppy#working-with-uppy-files [tus]: https://tus.io/ [`tusd`]: https://github.com/tus/tusd [implementations]: https://tus.io/implementations.html --- Source: https://uppy.io/docs/unsplash # Unsplash The `@uppy/unsplash` plugin lets users import files from their [Unsplash](https://unsplash.com) account. :::tip [Try out the live example](/examples) or take it for a spin in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-zaqyaf?file=main.js). ::: ## When should I use this? When you want to let users import files from their [Unsplash](https://unsplash.com) account. A [Companion](/docs/companion) instance is required for the Unsplash plugin to work. Companion handles authentication with Unsplash, downloads the files, and uploads them to the destination. This saves the user bandwidth, especially helpful if they are on a mobile connection. You can self-host Companion or get a hosted version with any [Transloadit plan](https://transloadit.com/pricing/). **NPM** ```shell npm install @uppy/unsplash ``` **Yarn** ```shell yarn add @uppy/unsplash ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use Using Unsplash requires setup in both Uppy and Companion. ### Use in Uppy ```js {10-13} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import Unsplash from '@uppy/unsplash'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(Unsplash, { companionUrl: 'https://your-companion.com' }); ``` ### Use with Transloadit ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Unsplash from '@uppy/unsplash'; uppy.use(Unsplash, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }); ``` You may also hit rate limits, because the OAuth application is shared between everyone using Transloadit. To solve that, you can use your own OAuth keys with Transloadit’s hosted Companion servers by using Transloadit Template Credentials. [Create a Template Credential][template-credentials] on the Transloadit site. Select “Companion OAuth” for the service, and enter the key and secret for the provider you want to use. Then you can pass the name of the new credentials to that provider: ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Unsplash from '@uppy/unsplash'; uppy.use(Unsplash, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'my_companion_dropbox_creds', }, }); ``` ### Use in Companion You can create a Unsplash App on the [Unsplash Developers site](https://unsplash.com/developers). You’ll be redirected to the app page, this page lists the app key and app secret. Configure the Unsplash key and secret. With the standalone Companion server, specify environment variables: ```shell export COMPANION_UNSPLASH_KEY="Unsplash API key" export COMPANION_UNSPLASH_SECRET="Unsplash API secret" ``` When using the Companion Node.js API, configure these options: ```js companion.app({ providerOptions: { unsplash: { key: 'Unsplash API key', secret: 'Unsplash API secret', }, }, }); ``` ## API ### Options #### `utmSource` Unsplash requires a `utm_source` query parameter when providing an attribution link to the author of the image (`string`, default: `'Companion'`). #### `id` A unique identifier for this plugin (`string`, default is a unique ID for each plugin). #### `title` Title / name shown in the UI, such as Dashboard tabs (`string`, default is the name of the plugin). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `companionUrl` URL to a [Companion](/docs/companion) instance (`string`, default: `null`). For Transloadit-hosted Companion use the `COMPANION_URL` constant exported by `@uppy/transloadit`, which is `https://api2.transloadit.com/companion`. Do not use a regional hostname such as `api2-eu-west-1.transloadit.com`: the OAuth flow then starts on one host and returns to another, and login fails with “Cannot find state in session”. #### `companionHeaders` Custom headers that should be sent along to [Companion](/docs/companion) on every request (`Object`, default: `{}`). #### `companionAllowedHosts` The valid and authorised URL(s) from which OAuth responses should be accepted (`string` or `RegExp` or `Array`). This option is useful when you have your [Companion](/docs/companion) running on several hosts. Otherwise, the default value should do fine, which uses the origin of `companionUrl`. This value can be a `string`, a `RegExp` pattern, or an `Array` of these. Strings are evaluated as regular expressions too and will be wrapped in a RegExp like so: ```js new RegExp(`^${value}$`); ``` **Important:** You must escape regex characters like `.`, or you might open your app up to security vulnerabilities. - Example correct strings - `'^(?:.*\\.)?example\.com$'` matches `example.com` and all of its subdomains. - `'https://example\.com'` matches `https://example.com` only. - Example vulnerability: `'https://www.example.com'` would allow an attacker with the domain `wwwxexample.com` to forge and inject a fraudulent token into Uppy. #### `companionKeysParams` Only applies to plugins that sign in through Companion (Google Drive, Dropbox, Box, OneDrive, …). The Google Drive Picker and Google Photos Picker ignore it; they authenticate directly with Google. Google Drive Picker uses its own `clientId`, `apiKey` and `appId`, while Google Photos Picker uses its own `clientId`. Use your own OAuth app with Transloadit-hosted Companion instead of Transloadit’s shared one (`Object`, default: `undefined`). It has two fields: - `key`: your Transloadit API key. - `credentialsName`: the name of a “Companion OAuth” credential you created in the Transloadit console, which holds the provider’s OAuth key and secret. ```js companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', } ``` Before the login popup opens, the plugin sends these values to Companion to obtain a pre-auth token, and Companion fetches the OAuth key and secret from Transloadit when the flow starts. The values are also sent along with every later request in a `uppy-credentials-params` header. Companion does not validate the credential name up front, so a wrong name only fails when a user tries to sign in. On Transloadit-hosted Companion this option is required for Google Drive, see [Google Drive: Use with Transloadit](/docs/google-drive#use-with-transloadit). #### `companionCookiesRule` This option correlates to the [RequestCredentials value](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials) (`string`, default: `'same-origin'`). This tells the plugin whether to send cookies to [Companion](/docs/companion). #### `locale` An object with `strings` property containing additional i18n strings. The key is the i18n key and the value is the English string. Example: ```js { strings: { someKey: 'Some English string', }, } ``` #### `storage` A custom storage to be used for the plugin’s persistent data. Type `AsyncStore`, default is `LocalStorage`. [template-credentials]: https://transloadit.com/docs/topics/template-credentials/ --- Source: https://uppy.io/docs/guides/uppy-transloadit # Use Uppy with Transloadit This is the canonical browser integration for sending user-selected files to a Transloadit Assembly—one execution of your Template. The same integration works in JavaScript, React, Next.js, Vue, and Angular. ## Know which part owns what - **Uppy is the open-source browser uploader.** It owns file selection, UI, restrictions, upload progress, and upload orchestration. You can use Uppy without Transloadit and point it at other upload destinations. - **Transloadit is the managed processing backend.** It receives files, runs the Assembly Instructions in your Template, and exports the results. A Transloadit account is required for this part. - **`@uppy/transloadit` is the bridge.** It creates an Assembly, configures the resumable upload, and can follow processing events from the browser. The Transloadit Auth Key and Template ID identify the account and workflow. The Auth Secret authorizes requests and **must never be included in browser code**. In production, have your server select an allowed Template and return signed, short-lived Assembly options to Uppy. ## 1. Create a Template Create a [Transloadit Template][first-app] before adding Uppy. Templates keep processing instructions on the managed backend, where browser users cannot replace the workflow. Copy its Template ID and set these server environment variables: ```shell TRANSLOADIT_KEY=your-auth-key TRANSLOADIT_SECRET=your-auth-secret TRANSLOADIT_TEMPLATE_ID=your-template-id ``` Do not prefix the secret with a framework convention that exposes environment variables to the browser, such as `NEXT_PUBLIC_`. ## 2. Sign Assembly options on your server Install the Transloadit Node SDK in the server application: ```shell npm install transloadit ``` This helper sets a one-hour expiration, then uses the SDK to add the Auth Key and calculate the signature over the exact serialized `params` value: ```ts title="server/transloadit-options.ts" import { Transloadit } from 'transloadit'; const authKey = process.env.TRANSLOADIT_KEY; const authSecret = process.env.TRANSLOADIT_SECRET; const templateId = process.env.TRANSLOADIT_TEMPLATE_ID; if (!authKey || !authSecret || !templateId) { throw new Error('Missing Transloadit server configuration'); } const transloadit = new Transloadit({ authKey, authSecret }); export function createAssemblyOptions() { const expires = new Date(Date.now() + 60 * 60 * 1000).toISOString(); const { params, signature } = transloadit.calcSignature({ auth: { expires }, template_id: templateId, }); return { params, signature }; } ``` Expose the return value from an authenticated `POST /api/transloadit-params` route. The route should enforce the current user’s upload permissions, rate limits, and allowed Template. Do not accept arbitrary `template_id`, `steps`, or storage credentials from the browser and sign them without validation. The signed options expire after one hour. Adjust that lifetime to the shortest window that still accommodates your users’ uploads. Every client example below uses the same function. Save it as `fetch-assembly-options.js` in a plain JavaScript application: ```ts title="fetch-assembly-options.ts" export async function fetchAssemblyOptions() { const response = await fetch('/api/transloadit-params', { method: 'POST' }); if (!response.ok) { throw new Error(`Could not prepare the upload (${response.status})`); } return response.json(); } ``` ## 3. Add the browser integration ### JavaScript ```shell npm install @uppy/core @uppy/dashboard @uppy/transloadit ``` ```js title="uploader.js" import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import Transloadit from '@uppy/transloadit'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; import { fetchAssemblyOptions } from './fetch-assembly-options.js'; const uppy = new Uppy() .use(Dashboard, { inline: true, target: '#uppy', }) .use(Transloadit, { assemblyOptions: fetchAssemblyOptions, // Keep the UI waiting only when browser code needs the final results. waitForEncoding: true, }); uppy.on('transloadit:complete', (assembly) => { // Results are keyed by the Step names declared in your Template. console.log('Assembly results:', assembly.results); }); ``` ```html title="index.html"
``` ### React ```shell npm install @uppy/core @uppy/dashboard @uppy/react @uppy/transloadit ``` ```tsx title="Uploader.tsx" import Uppy from '@uppy/core'; import Dashboard from '@uppy/react/dashboard'; import Transloadit from '@uppy/transloadit'; import { useState, type ReactNode } from 'react'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; import { fetchAssemblyOptions } from './fetch-assembly-options'; function createUppy() { return new Uppy().use(Transloadit, { assemblyOptions: fetchAssemblyOptions, }); } export function Uploader(): ReactNode { const [uppy] = useState(createUppy); return ; } ``` Create the Uppy instance once. Recreating it during a render loses selected files and may interrupt active uploads. Lift the instance to a longer-lived provider if uploads must continue while routes change. ### Next.js ```shell npm install @uppy/core @uppy/dashboard @uppy/react @uppy/transloadit transloadit ``` Keep the signing helper in server-only code, then expose it with an App Router route: ```ts title="app/api/transloadit-params/route.ts" import { NextResponse } from 'next/server'; import { createAssemblyOptions } from '../../../server/transloadit-options'; export async function POST(): Promise { // Authenticate the request and authorize this upload before signing. return NextResponse.json(createAssemblyOptions()); } ``` The Uppy component needs the client boundary because it uses browser APIs: ```tsx title="app/upload/Uploader.tsx" 'use client'; import Uppy from '@uppy/core'; import Dashboard from '@uppy/react/dashboard'; import Transloadit from '@uppy/transloadit'; import { useState, type ReactNode } from 'react'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; import { fetchAssemblyOptions } from './fetch-assembly-options'; function createUppy() { return new Uppy().use(Transloadit, { assemblyOptions: fetchAssemblyOptions, }); } export function Uploader(): ReactNode { const [uppy] = useState(createUppy); return ; } ``` ### Vue ```shell npm install @uppy/core @uppy/dashboard @uppy/transloadit @uppy/vue ``` ```vue title="Uploader.vue" ``` ### Angular ```shell npm install @uppy/angular @uppy/core @uppy/dashboard @uppy/transloadit ``` ```ts title="uploader.component.ts" import { Component, type OnDestroy } from '@angular/core'; import { DashboardComponent } from '@uppy/angular'; import Uppy from '@uppy/core'; import Transloadit from '@uppy/transloadit'; import { fetchAssemblyOptions } from './fetch-assembly-options'; @Component({ selector: 'app-uploader', standalone: true, imports: [DashboardComponent], template: '', }) export class UploaderComponent implements OnDestroy { readonly uppy = new Uppy().use(Transloadit, { assemblyOptions: fetchAssemblyOptions, }); ngOnDestroy(): void { this.uppy.destroy(); } } ``` Load the Uppy styles once in the application’s global stylesheet: ```css title="styles.css" @import '@uppy/core/css/style.min.css'; @import '@uppy/dashboard/css/style.min.css'; ``` The React, Next.js, Vue, and Angular examples intentionally use the default `waitForEncoding: false`. Only the JavaScript example opts in to waiting because it demonstrates reading final results in browser code. ## 4. Decide when the UI is finished The default `waitForEncoding: false` marks the Uppy upload complete after the files reach Transloadit, while the Assembly may still be processing. For long jobs, configure a [`notify_url`][webhooks] in your server-owned Assembly Instructions or Template—not as an Uppy plugin option. Verify the notification signature on your server and update your application asynchronously. Use `waitForEncoding: true` only when the user should remain on the page until the final Assembly results are available. Listen to [`transloadit:result` and `transloadit:complete`][plugin-events] when waiting in the browser; these events are emitted only with `waitForEncoding: true`. To reconcile processing after a navigation or connection loss, listen to `transloadit:assembly-created` and save `assembly.assembly_id` in your application. ## 5. Add remote sources only when needed Dropbox, Google Drive, URL imports, and similar sources need Companion. A Transloadit plan includes a hosted Companion service. Point each remote-source provider plugin at it by assigning the `COMPANION_URL` and `COMPANION_ALLOWED_HOSTS` constants exported by `@uppy/transloadit` to the plugin’s `companionUrl` and `companionAllowedHosts` options. See the [Companion configuration example][companion]. Local-device uploads do not need Companion. Google Drive is the one source that does not work out of the box: Google has blocked Transloadit’s shared OAuth app, so you must register your own and store it as a Transloadit credential. See [Google Drive: Use with Transloadit][google-drive-transloadit], or use the [Google Drive Picker][google-drive-picker] plugin, which uses a non-restricted scope and needs no Google verification (it still needs your own Google client ID, API key and app ID). Continue with the [complete plugin API][plugin-api], the [runnable Transloadit example][runnable-example], or the [Transloadit-side Uppy guide][transloadit-uppy]. [first-app]: https://transloadit.com/docs/getting-started/my-first-app/ [companion]: /docs/transloadit#use-with-companion [google-drive-transloadit]: /docs/google-drive#use-with-transloadit [google-drive-picker]: /docs/google-drive-picker [plugin-api]: /docs/transloadit [plugin-events]: /docs/transloadit#events [runnable-example]: https://github.com/transloadit/uppy/tree/main/examples/transloadit [transloadit-uppy]: https://transloadit.com/docs/sdks/uppy/ [webhooks]: https://transloadit.com/docs/topics/webhooks/ --- Source: https://uppy.io/docs/uppy # Uppy core Uppy can be an uploader and an interface with a lot of features. Features can be added incrementally with plugins, but Uppy can be as bare bones as you want it to be. So we build Uppy’s heart, `@uppy/core`, as a standalone orchestrator. It acts as a state manager, event emitter, and restrictions handler. ## When should I use it? `@uppy/core` is the fundament of the Uppy ecosystem, the orchestrator for all added plugins. No matter the uploading experience you’re looking for, it all starts with installing this plugin. You can use `@uppy/core` and [build your own UI](/docs/guides/building-your-own-ui-with-uppy) or go for the [Dashboard](/docs/dashboard) integration. For an uploading plugin, you can refer to [choosing the uploader you need](/docs/guides/choosing-uploader). If you want to see how it all comes together, checkout the [examples](/examples). ## Install **NPM** ```shell npm install @uppy/core ``` **Yarn** ```shell yarn add @uppy/core ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use `@uppy/core` has four exports: `Uppy`, `UIPlugin`, `BasePlugin`, and `debugLogger`. The default export is the `Uppy` class. ### Working with Uppy files Uppy keeps files in state with the [`File`][] browser API, but it’s wrapped in an `Object` to be able to add more data to it, which we call an _Uppy file_. All these properties can be useful for plugins and side-effects (such as [events](#events)). Mutating these properties should be done through [methods](#methods).
Uppy file properties #### `file.source` Name of the plugin that was responsible for adding this file. Typically a remote provider plugin like `'GoogleDrive'` or a UI plugin like `'DragDrop'`. #### `file.id` Unique ID for the file. #### `file.name` The name of the file. #### `file.meta` Object containing standard as well as user-defined metadata for each file. Any custom file metadata should be JSON-serializable. The following standard metadata will be stored on all file objects, but plugins may add more metadata. - `file.meta.name` - Same as `file.name`. - `file.meta.type` - Same as `file.type`. - `file.meta.relativePath` - For any local folder that was drag-dropped or opened in Uppy, the files inside the folder will have the `relativePath` metadata field set to their path, relative to the folder. `relativePath` begins with the folder’s name and ends with the file’s name. If opening or drag-dropping a file instead of a folder, `relativePath` will be `null`. The same behaviour exists for remote (provider) files, but the path will instead be relative to the user’s selection (checkboxes). No leading or trailing slashes. - **Local file example:** When drag-dropping a local folder `folder1` which has a folder inside of it named `folder2` which has a file named `file` inside of it, the `relativePath` meta field of the file will be `folder1/folder2/file`. However if drag-dropping or opening `file` directly, `relativePath` will be `null`. - **Remote file example:** Suppose we have a remote provider folder structure such as `/folder1/folder2/file`. Then, if the user checks the checkbox next to `folder1`, `file`’s `relativePath` will be `"folder1/folder2/file"`. However if the user first navigates into `folder1`, and only then checks the checkbox next to `folder2`, `relativePath` will be `"folder2/file"`. - `file.meta.absolutePath` - The `absolutePath` meta field will only be set for remote files. Regardless of user selection, it will always be the path relative to the root of the provider’s list of files, as presented to the user. `absolutePath` always begins with a `/` and will always end with the file’s name. To clarify: The difference between `absolutePath` and `relativePath` is that `absolutePath` only exists for remote files, and always has the full path to the file, while `relativePath` is the file’s path _relative to the user’s selected folder_. #### `file.type` MIME type of the file. This may actually be guessed if a file type was not provided by the user’s browser, so this is a best-effort value and not guaranteed to be correct. #### `file.data` For local files, this is the actual [`File`][] or [`Blob`][] object representing the file contents. For files that are imported from remote providers, the file data is not available in the browser. [`file`]: https://developer.mozilla.org/en-US/docs/Web/API/File [`blob`]: https://developer.mozilla.org/en-US/docs/Web/API/Blob #### `file.progress` An object with upload progress data. **Properties** - `bytesUploaded` - Number of bytes uploaded so far. - `bytesTotal` - Number of bytes that must be uploaded in total. - `uploadStarted` - Null if the upload has not started yet. Once started, this property stores a UNIX timestamp. Note that this is only set _after_ preprocessing. - `uploadComplete` - Boolean indicating if the upload has completed. Note this does _not_ mean that postprocessing has completed, too. - `percentage` - Integer percentage between 0 and 100. #### `file.size` Size in bytes of the file. #### `file.isRemote` Boolean: is this file imported from a remote provider? #### `file.remote` Grab bag of data for remote providers. Generally not interesting for end users. #### `file.preview` An optional URL to a visual thumbnail for the file. #### `file.uploadURL` When an upload is completed, this may contain a URL to the uploaded file. Depending on server configuration it may not be accessible or correct.
## `new Uppy(options?)` ```js import Uppy from '@uppy/core'; const uppy = new Uppy(); ``` ### Options #### `id` A site-wide unique ID for the instance (`string`, default: `uppy`). :::note If several Uppy instances are being used, for instance, on two different pages, an `id` should be specified. This allows Uppy to store information in `localStorage` without colliding with other Uppy instances. This ID should be persistent across page reloads and navigation. It shouldn’t be a random number that is different every time Uppy is loaded. ::: #### `autoProceed` Upload as soon as files are added (`boolean`, default: `false`). By default Uppy will wait for an upload button to be pressed in the UI, or the `.upload()` method to be called before starting an upload. Setting this to `true` will start uploading automatically after the first file is selected #### `allowMultipleUploadBatches` Whether to allow several upload batches (`boolean`, default: `true`). This means several calls to `.upload()`, or a user adding more files after already uploading some. An upload batch is made up of the files that were added since the earlier `.upload()` call. With this option set to `true`, users can upload some files, and then add _more_ files and upload those as well. A model use case for this is uploading images to a gallery or adding attachments to an email. With this option set to `false`, users can upload some files, and you can listen for the [`'complete'`](#complete) event to continue to the next step in your app’s upload flow. A typical use case for this is uploading a new profile picture. If you are integrating with an existing HTML form, this option gives the closest behaviour to a bare ``. #### `debug` Whether to send debugging and warning logs (`boolean`, default: `false`). Setting this to `true` sets the [`logger`](#logger) to [`debugLogger`](#debuglogger). #### `logger` Logger used for [`uppy.log`](#logmessage-type) (`Object`, default: `justErrorsLogger`). By providing your own `logger`, you can send the debug information to a server, choose to log errors only, etc. :::note Set `logger` to [`debugLogger`](#debuglogger) to get debug info output to the browser console: ::: :::note You can also provide your own logger object: it should expose `debug`, `warn` and `error` methods, as shown in the examples below. Here’s an example of a `logger` that does nothing: ```js const nullLogger = { debug: (...args) => {}, warn: (...args) => {}, error: (...args) => {}, }; ``` ::: #### `restrictions` Conditions for restricting an upload (`Object`, default: `{}`). | Property | Value | Description | | -------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `maxFileSize` | `number` | maximum file size in bytes for each individual file | | `minFileSize` | `number` | minimum file size in bytes for each individual file | | `maxTotalFileSize` | `number` | maximum file size in bytes for all the files that can be selected for upload | | `maxNumberOfFiles` | `number` | total number of files that can be selected | | `minNumberOfFiles` | `number` | minimum number of files that must be selected before the upload | | `allowedFileTypes` | `Array` | wildcards `image/*`, or exact mime types `image/jpeg`, or file extensions `.jpg`: `['image/*', '.jpg', '.jpeg', '.png', '.gif']` | | `requiredMetaFields` | `Array` | make keys from the `meta` object in every file required before uploading | :::note `maxNumberOfFiles` also affects the number of files a user is able to select via the system file dialog in UI plugins like `DragDrop`, `FileInput` and `Dashboard`. When set to `1`, they will only be able to select a single file. When `null` or another number is provided, they will be able to select several files. ::: :::note `allowedFileTypes` gets passed to the file system dialog via the [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Limiting_accepted_file_types) accept attribute, so only types supported by the browser will work. Uppy does not do content-based file type sniffing by default. For local files, it relies on the browser-provided `File.type`, and if that is unavailable, it falls back to the file extension. This means `allowedFileTypes` is best used as client-side guidance and UX, not as authoritative validation. ::: :::tip If you’d like to force a certain meta field data to be entered before the upload, you can [do so using `onBeforeUpload`](https://github.com/transloadit/uppy/issues/1703#issuecomment-507202561). ::: :::tip If you need to restrict `allowedFileTypes` to a file extension with double dots, like `.nii.gz`, you can do so by [setting `allowedFileTypes` to the last part of the extension, `allowedFileTypes: ['.gz']`, and then using `onBeforeFileAdded` to filter for `.nii.gz`](https://github.com/transloadit/uppy/issues/1822#issuecomment-526801208). ::: #### `meta` Key/value pairs to add to each file’s `metadata` (`Object`, default: `{}`). :::note Metadata from each file is then attached to uploads in the [Tus](/docs/tus) and [XHR](/docs/xhr-upload) plugins. ::: :::info Two methods also exist for updating `metadata`: [`setMeta`](#setmetadata) and [`setFileMeta`](#setfilemetafileid-data). ::: :::info Metadata can also be added from a `` element on your page, through the [Form](#) plugin or through the UI if you are using Dashboard with the [`metaFields`](/docs/dashboard#metafields) option. ::: #### `onBeforeFileAdded(file, files)` A function called before a file is added to Uppy (`Function`, default: `(file, files) => !Object.hasOwn(files, file.id)`). Use this function to run any number of custom checks on the selected file, or manipulate it, for instance, by optimizing a file name. You can also allow duplicate files with this. If you need stricter client-side checks than `allowedFileTypes` provides, this is the right place to add them. Even then, you should still validate file types on the server. You can return `true` to keep the file as is, `false` to remove the file, or return a modified file. :::caution This method is intended for quick synchronous checks and modifications only. If you need to do an async API call, or heavy work on a file (like compression or encryption), you should use a [custom plugin](/docs/guides/building-plugins) instead. ::: :::info No notification will be shown to the user about a file not passing validation by default. We recommend showing a message using [`uppy.info()`](#infomessage-type-duration) and logging to console for debugging purposes via [`uppy.log()`](#logmessage-type). :::
Filter, change, and abort example Allow all files, also duplicate files. This will replace the file if it has not been uploaded. If you upload a duplicate file again it depends on your upload plugin and backend how it is handled. ```js const uppy = new Uppy({ // ... onBeforeFileAdded: () => true, ``` Keep only files under a condition: ```js const uppy = new Uppy({ // ... onBeforeFileAdded: (currentFile, files) => { if (currentFile.name === 'forest-IMG_0616.jpg') { return true } return false }, ``` Change all file names: ```js const uppy = new Uppy({ // ... onBeforeFileAdded: (currentFile, files) => { const modifiedFile = { ...currentFile, name: `${currentFile.name}__${Date.now()}`, } return modifiedFile }, ``` Abort a file: ```js const uppy = new Uppy({ // ... onBeforeFileAdded: (currentFile, files) => { if (!currentFile.type) { // log to console uppy.log(`Skipping file because it has no type`); // show error message to the user uppy.info(`Skipping file because it has no type`, 'error', 500); return false; } }, }); ```
#### `onBeforeUpload(files)` A function called before when upload is initiated (`Function`, default: `(files) => files`). Use this to check if all files or their total number match your requirements, or manipulate all the files at once before upload. You can return `true` to continue the upload, `false` to cancel it, or return modified files. :::caution This method is intended for quick synchronous checks and modifications only. If you need to do an async API call, or heavy work on a file (like compression or encryption), you should use a [custom plugin](/docs/guides/building-plugins) instead. ::: :::info No notification will be shown to the user about a file not passing validation by default. We recommend showing a message using [`uppy.info()`](#infomessage-type-duration) and logging to console for debugging purposes via [`uppy.log()`](#logmessage-type). :::
Change and abort example Change all file names: ```js const uppy = new Uppy({ // ... onBeforeUpload: (files) => { // We’ll be careful to return a new object, not mutating the original `files` const updatedFiles = {}; Object.keys(files).forEach((fileID) => { updatedFiles[fileID] = { ...files[fileID], name: `${myCustomPrefix}__${files[fileID].name}`, }; }); return updatedFiles; }, }); ``` Abort an upload: ```js const uppy = new Uppy({ // ... onBeforeUpload: (files) => { if (Object.keys(files).length < 2) { // log to console uppy.log( `Aborting upload because only ${ Object.keys(files).length } files were selected`, ); // show error message to the user uppy.info(`You have to select at least 2 files`, 'error', 500); return false; } return true; }, }); ```
#### `locale` You can override locale strings by passing the `strings` object with the keys you want to override. :::note Array indexed objects are used for pluralisation. ::: :::info If you want a different language it’s better to use [locales](/docs/locales). ::: ```js module.exports = { strings: { addBulkFilesFailed: { 0: 'Failed to add %{smart_count} file due to an internal error', 1: 'Failed to add %{smart_count} files due to internal errors', }, youCanOnlyUploadX: { 0: 'You can only upload %{smart_count} file', 1: 'You can only upload %{smart_count} files', }, youHaveToAtLeastSelectX: { 0: 'You have to select at least %{smart_count} file', 1: 'You have to select at least %{smart_count} files', }, exceedsSize: '%{file} exceeds maximum allowed size of %{size}', missingRequiredMetaField: 'Missing required meta fields', missingRequiredMetaFieldOnFile: 'Missing required meta fields in %{fileName}', inferiorSize: 'This file is smaller than the allowed size of %{size}', youCanOnlyUploadFileTypes: 'You can only upload: %{types}', noMoreFilesAllowed: 'Cannot add more files', noDuplicates: "Cannot add the duplicate file '%{fileName}', it already exists", companionError: 'Connection with Companion failed', authAborted: 'Authentication aborted', companionUnauthorizeHint: 'To unauthorize to your %{provider} account, please go to %{url}', failedToUpload: 'Failed to upload %{file}', noInternetConnection: 'No Internet connection', connectedToInternet: 'Connected to the Internet', // Strings for remote providers noFilesFound: 'You have no files or folders here', selectX: { 0: 'Select %{smart_count}', 1: 'Select %{smart_count}', }, allFilesFromFolderNamed: 'All files from folder %{name}', openFolderNamed: 'Open folder %{name}', cancel: 'Cancel', logOut: 'Log out', filter: 'Filter', resetFilter: 'Reset filter', loading: 'Loading...', authenticateWithTitle: 'Please authenticate with %{pluginName} to select files', authenticateWith: 'Connect to %{pluginName}', signInWithGoogle: 'Sign in with Google', searchImages: 'Search for images', enterTextToSearch: 'Enter text to search for images', search: 'Search', emptyFolderAdded: 'No files were added from empty folder', folderAlreadyAdded: 'The folder "%{folder}" was already added', folderAdded: { 0: 'Added %{smart_count} file from %{folder}', 1: 'Added %{smart_count} files from %{folder}', }, }, }; ``` #### `store` The store that is used to keep track of internal state (`Object`, default: [`DefaultStore`](/docs/guides/custom-stores)). This option can be used to plug Uppy state into an external state management library, such as [Redux](/docs/guides/custom-stores). {/* TODO document store API */} #### `infoTimeout` How long an [Informer](/docs/informer) notification will be visible (`number`, default: `5000`). ### Methods #### `use(plugin, opts)` Add a plugin to Uppy, with an optional plugin options object. ```js import Uppy from '@uppy/core'; import DragDrop from '@uppy/drag-drop'; const uppy = new Uppy(); uppy.use(DragDrop, { target: 'body' }); ``` #### `removePlugin(instance)` Uninstall and remove a plugin. #### `getPlugin(id)` Get a plugin by its `id` to access its methods. #### `getID()` Get the Uppy instance ID, see the [`id`](#id) option. #### `addFile(file)` Add a new file to Uppy’s internal state. `addFile` will return the generated id for the file that was added. `addFile` gives an error if the file cannot be added, either because `onBeforeFileAdded(file)` gave an error, or because `uppy.opts.restrictions` checks failed. It throws on the first error, including restriction errors. Every `addFile` call emits both `file-added` and `files-added`, with `files-added` carrying a single-element array. When adding more than one file at a time, prefer [`addFiles(files)`](#addfilesfiles) so that batch listeners on `files-added` fire exactly once and a restriction failure on one file does not abort the whole batch. ```js uppy.addFile({ name: 'my-file.jpg', // file name type: 'image/jpeg', // file type data: blob, // file blob meta: { // optional, store the directory path of a file so Uppy can tell identical files in different directories apart. relativePath: webkitFileSystemEntry.relativePath, }, source: 'Local', // optional, determines the source of the file, for example, Dropbox. isRemote: false, // optional, set to true if actual file is not in the browser, but on some remote server, for example, // when using companion in combination with Dropbox. }); ``` :::note If you try to add a file that already exists, `addFile` will throw an error, unless that duplicate file was dropped with a folder. Duplicate files from different folders are allowed, when selected with that folder. This is because we add `file.meta.relativePath` to the `file.id`. ::: :::info Checkout [working with Uppy files](#working-with-uppy-files). ::: :::info If `uppy.opts.autoProceed === true`, Uppy will begin uploading automatically when files are added. ::: :::info Sometimes you might need to add a remote file to Uppy. This can be achieved by [fetching the file, then creating a Blob object, or using the Url plugin with Companion](https://github.com/transloadit/uppy/issues/1006#issuecomment-413495493). ::: :::info Sometimes you might need to mark some files as “already uploaded”, so that the user sees them, but they won’t actually be uploaded by Uppy. This can be achieved by [looping through files and setting `uploadComplete: true, uploadStarted: true` on them](https://github.com/transloadit/uppy/issues/1112#issuecomment-432339569) ::: #### `addFiles(files)` Add multiple files to Uppy’s internal state in one call. Each entry in `files` takes the same shape as the argument to [`addFile`](#addfilefile). ```js uppy.addFiles([ { name: 'photo-1.jpg', type: 'image/jpeg', data: blob1 }, { name: 'photo-2.jpg', type: 'image/jpeg', data: blob2 }, ]); ``` Events and errors behave differently from a loop of `addFile` calls, which is the main reason to use this method for batch adds: - Emits `file-added` once per accepted file. - Emits `files-added` **once** for the whole batch, with the array of accepted files. - Restriction failures (file too big, wrong type, too many files, etc.) emit `restriction-failed` for each failing file and surface an info message: **they do not throw**, and valid files in the same batch are still added. - Any non-restriction error (for example, an exception thrown from `onBeforeFileAdded`) is aggregated into an `AggregateError` (available on the thrown error’s `.errors` property) and thrown **before state is updated**. When this happens, **no files from the batch are added** and `files-added` is not emitted. Prefer `addFiles` over calling `addFile` in a loop when adding multiple files: batch listeners on `files-added` fire exactly once, and restriction failures on individual files do not abort the batch. Note that non-restriction errors still abort the batch before any files are added, so if you need partial-success semantics for arbitrary failures you’ll need to call `addFile` per file with your own error handling. #### `removeFile(fileID)` Remove a file from Uppy. Removing a file that is already being uploaded cancels that upload. ```js uppy.removeFile('uppyteamkongjpg1501851828779'); ``` #### `clear()` Clear the state. Can be useful for manually resetting Uppy after a successful upload. Note that this method might throw an error if you try to call it while an upload is ongoing. Upload plugins may choose to throw an error if called during an upload. #### `getFile(fileID)` Get a specific [Uppy file](#working-with-uppy-files) by its ID. ```js const file = uppy.getFile('uppyteamkongjpg1501851828779'); ``` #### `getFiles()` Get an array of all added [Uppy files](#working-with-uppy-files). ```js const files = uppy.getFiles(); ``` #### `upload()` Start uploading added files. Returns a Promise `result` that resolves with an object containing two arrays of uploaded files: - `result.successful` - Files that were uploaded successfully. - `result.failed` - Files that did not upload successfully. These files will have a `.error` property describing what went wrong. ```js uppy.upload().then((result) => { console.info('Successful uploads:', result.successful); if (result.failed.length > 0) { console.error('Errors:'); result.failed.forEach((file) => { console.error(file.error); }); } }); ``` #### `pauseResume(fileID)` Toggle pause/resume on an upload. Will only work if resumable upload plugin, such as [Tus](/docs/tus/), is used. #### `pauseAll()` Pause all uploads. Will only work if a resumable upload plugin, such as [Tus](/docs/tus/), is used. #### `resumeAll()` Resume all uploads. Will only work if resumable upload plugin, such as [Tus](/docs/tus/), is used. #### `retryUpload(fileID)` Retry an upload (after an error, for example). #### `retryAll()` Retry all uploads (after an error, for example). #### `cancelAll()` Cancel all uploads, reset progress and remove all files. If you are using the Transloadit plugin, this will also cancel all running assemblies, even after an upload has finished. #### `setState(patch)` Update Uppy’s internal state. Usually, this method is called internally, but in some cases it might be useful to alter something directly, especially when implementing your own plugins. Uppy’s default state on initialization: ```js const state = { plugins: {}, files: {}, currentUploads: {}, capabilities: { resumableUploads: false, }, totalProgress: 0, meta: { ...this.opts.meta }, info: { isHidden: true, type: 'info', message: '', }, }; ``` Updating state: ```js uppy.setState({ smth: true }); ``` :::note State in Uppy is considered to be immutable. When updating values, make sure not mutate them, but instead create copies. See [Redux docs](http://redux.js.org/docs/recipes/UsingObjectSpreadOperator.html) for more info on this. ::: #### `getState()` Returns the current state from the [Store](#store). #### `setFileState(fileID, state)` Update the state for a single file. This is mostly useful for plugins that may want to store data on [Uppy files](#working-with-uppy-files), or need to pass file-specific configurations to other plugins that support it. `fileID` is the string file ID. `state` is an object that will be merged into the file’s state object. #### `setMeta(data)` Alters global `meta` object in state, the one that can be set in Uppy options and gets merged with all newly added files. Calling `setMeta` will also merge newly added meta data with files that had been selected before. ```js uppy.setMeta({ resize: 1500, token: 'ab5kjfg' }); ``` #### `setFileMeta(fileID, data)` Update metadata for a specific file. ```js uppy.setFileMeta('myfileID', { resize: 1500 }); ``` #### `setOptions(opts)` Change the options Uppy initialized with. ```js const uppy = new Uppy(); uppy.setOptions({ restrictions: { maxNumberOfFiles: 3 }, autoProceed: true, }); uppy.setOptions({ locale: { strings: { cancel: 'Отмена', }, }, }); ``` You can also change options for plugin: ```js // Change width of the Dashboard drag-and-drop aread on the fly uppy.getPlugin('Dashboard').setOptions({ width: 300, }); ``` #### `destroy()` Uninstall all plugins and close down this Uppy instance. Also runs `uppy.cancelAll()` before uninstalling. Note that this method should not normally be used. If you only want reset the Uppy instance so that you can start a new upload, you probably want to use `clear()` method instead. #### `logout()` Calls `provider.logout()` on each remote provider plugin (Google Drive, Dropbox, etc). Useful, for example, after your users log out of their account in your app. This will clean things up with Uppy cloud providers as well, for extra security. #### `log(message, type)` | Argument | Type | Description | | --------- | --------- | --------------------------- | | `message` | `string` | message to log | | `type` | `string?` | `debug`, `warn`, or `error` | See [`logger`](#logger) docs for details. ```js uppy.log('[Dashboard] adding files...'); ``` #### `info(message, type, duration)` Sets a message in state, with optional details, that can be shown by notification UI plugins. It’s using the [Informer](/docs/informer) plugin, included by default in Dashboard. | Argument | Type | Description | | ---------- | ------------------ | --------------------------------------------------------------------------------- | | `message` | `string`, `Object` | `'info message'` or `{ message: 'Oh no!', details: 'File couldn’t be uploaded' }` | | `type` | `string?` | `'info'`, `'warning'`, `'success'` or `'error'` | | `duration` | `number?` | in milliseconds | `info-visible` and `info-hidden` events are emitted when this info message should be visible or hidden. ```js this.info('Oh my, something good happened!', 'success', 3000); ``` ```js this.info( { message: 'Oh no, something bad happened!', details: 'File couldn’t be uploaded because there is no internet connection', }, 'error', 5000, ); ``` #### `addPreProcessor(fn)` Add a preprocessing function. `fn` gets called with a list of file IDs before an upload starts. `fn` should return a Promise. Its resolution value is ignored. :::info To change file data and such, use Uppy state updates, for example using [`setFileState`](#setfilestatefileid-state). ::: #### `addUploader(fn)` Add an uploader function. `fn` gets called with a list of file IDs when an upload should start. Uploader functions should do the actual uploading work, such as creating and sending an XMLHttpRequest or calling into some upload service SDK. `fn` should return a Promise that resolves once all files have been uploaded. :::tip You may choose to still resolve the Promise if some file uploads fail. This way, any postprocessing will still run on the files that were uploaded successfully, while uploads that failed will be retried when [`retryAll`](#retryall) is called. ::: #### `addPostProcessor(fn)` Add a postprocessing function. `fn` is called with a list of file IDs when an upload has finished. `fn` should return a Promise that resolves when the processing work is complete. The value of the Promise is ignored. For example, you could wait for file encoding or CDN propagation to complete, or you could do an HTTP API call to create an album containing all images that were uploaded. #### `removePreProcessor/removeUploader/removePostProcessor(fn)` Remove a processor or uploader function that was added before. Normally, this should be done in the [`uninstall()`](#uninstall) method. #### `on('event', action)` Subscribe to an uppy-event. See below for the full list of events. #### `once('event', action)` Create an event listener that fires once. See below for the full list of events. #### `off('event', action)` Unsubscribe to an uppy-event. See below for the full list of events. ### Events Uppy exposes events that you can subscribe to for side-effects. #### `file-added` Fired each time a file is added. **Parameters** - `file` - The [Uppy file](#working-with-uppy-files) that was added. ```js uppy.on('file-added', (file) => { console.log('Added file', file); }); ``` #### `files-added` **Parameters** - `files` - Array of [Uppy files](#working-with-uppy-files) which were added at once, in a batch. Fired each time one or more files are added. A single [`addFiles`](#addfilesfiles) call emits one `files-added` event for the whole batch; an [`addFile`](#addfilefile) call emits one `files-added` event with a single-element array. Looping `addFile` therefore produces N `files-added` events; use `addFiles` instead if you want a single batch event. #### `file-removed` Fired each time a file is removed. **Parameters** - `file` - The [Uppy file](#working-with-uppy-files) that was removed. **Example** ```js uppy.on('file-removed', (file) => { console.log('Removed file', file); }); ``` ```js uppy.on('file-removed', (file) => { removeFileFromUploadingCounterUI(file); sendDeleteRequestForFile(file); }); ``` #### `upload` Fired when the upload starts. **Parameters** - `uploadID` (`string)` - `files` (`UppyFile`) #### `preprocess-progress` Progress of the pre-processors. **Parameters** `progress` is an object with properties: - `mode` - Either `'determinate'` or `'indeterminate'`. - `message` - A message to show to the user. Something like `'Preparing upload...'`, but be more specific if possible. When `mode` is `'determinate'`, also add the `value` property: - `value` - A progress value between 0 and 1. #### `progress` Fired each time the total upload progress is updated: **Parameters** - `progress` - An integer (0-100) representing the total upload progress. **Example** ```js uppy.on('progress', (progress) => { // progress: integer (total progress percentage) console.log(progress); }); ``` #### `upload-progress` Fired each time an individual file upload progress is available: **Parameters** - `file` - The [Uppy file](#working-with-uppy-files) that has progressed. - `progress` - The same object as in `file.progress`. **Example** ```js uppy.on('upload-progress', (file, progress) => { // file: { id, name, type, ... } // progress: { uploader, bytesUploaded, bytesTotal } console.log(file.id, progress.bytesUploaded, progress.bytesTotal); }); ``` #### `upload-pause` Fired when an individual upload is (un)paused. **Parameters** - `file` (`UppyFile`) - `isPaused` (`boolean`) #### `postprocess-progress` Progress of the post-processors. **Parameters** `progress` is an object with properties: - `mode` - Either `'determinate'` or `'indeterminate'`. - `message` - A message to show to the user. Something like `'Preparing upload...'`, but be more specific if possible. When `mode` is `'determinate'`, also add the `value` property: - `value` - A progress value between 0 and 1. #### `upload-success` Fired each time a single upload is completed. **Parameters** - `file` - The [Uppy file](#working-with-uppy-files) that was uploaded. - `response` - An object with response data from the remote endpoint. The actual contents depend on the upload plugin that is used. For `@uppy/xhr-upload`, the shape is: ```json { "status": 200, // HTTP status code (0, 200, 300) "body": "…", // response body "uploadURL": "…" // the file url, if it was returned } ``` **Example** ```js uppy.on('upload-success', (file, response) => { console.log(file.name, response.uploadURL); const img = new Image(); img.width = 300; img.alt = file.id; img.src = response.uploadURL; document.body.appendChild(img); }); ``` #### `complete` Fired when an upload is complete and all files belonging to that upload have completed uploading. Note that this event also gets fired if some or all files have failed. It is emitted once per upload and contains the unique ID of the particular upload. The `result` parameter is an object with arrays of `successful` and `failed` files, as in [`uppy.upload()`](#upload)’s return value. ```js uppy.on('complete', (result) => { console.log('successful files:', result.successful); console.log('failed files:', result.failed); }); ``` #### `error` Fired when Uppy fails to upload/encode the entire upload. **Parameters** - `error` - The error object. **Example** ```js uppy.on('error', (error) => { console.error(error.stack); }); ``` #### `upload-error` Fired each time a single upload failed. **Parameters** - `file` - The [Uppy file](#working-with-uppy-files) which didn’t upload. - `error` - The error object. - `response` - an optional parameter with response data from the upload endpoint. It may be undefined or contain different data depending on the upload plugin in use. For `@uppy/xhr-upload`, the shape is: ```json { "status": 200, // HTTP status code (0, 200, 300) "body": "…" // response body } ``` **Example** ```js uppy.on('upload-error', (file, error, response) => { console.log('error with file:', file.id); console.log('error message:', error); }); ``` If the error is related to network conditions (endpoint unreachable due to firewall or ISP blockage, for instance), the error will have `error.isNetworkError` property set to `true`. Here’s how you can check for network errors: ```js uppy.on('upload-error', (file, error, response) => { if (error.isNetworkError) { // Let your users know that file upload could have failed // due to firewall or ISP issues alertUserAboutPossibleFirewallOrISPIssues(error); } }); ``` #### `upload-retry` Fired when an upload has been retried (after an error, for example). :::note This event is not triggered when the user retries all uploads, it will trigger the `retry-all` event instead. ::: **Parameters** - `file` (`UppyFile`) **Example** ```js uppy.on('upload-retry', (fileID) => { console.log('upload retried:', fileID); }); ``` #### `upload-stalled` Fired when an upload has not received any progress in some time (in `@uppy/xhr-upload`, the delay is defined by the `timeout` option). Use this event to display a message on the UI to tell the user they might want to retry the upload. ```js uppy.on('upload-stalled', (error, files) => { console.log('upload seems stalled', error, files); const noLongerStalledEventHandler = (file) => { if (files.includes(file)) { console.log('upload is no longer stalled'); uppy.off('upload-progress', noLongerStalledEventHandler); } }; uppy.on('upload-progress', noLongerStalledEventHandler); }); ``` #### `retry-all` Fired when all failed uploads are retried **Parameters** - `files` (`UppyFile[]`) **Example** ```js uppy.on('retry-all', (fileIDs) => { console.log('upload retried:', fileIDs); }); ``` #### `info-visible` Fired when “info” message should be visible in the UI. By default, `Informer` plugin is displaying these messages (enabled by default in `Dashboard` plugin). You can use this event to show messages in your custom UI: ```js uppy.on('info-visible', () => { const { info } = uppy.getState(); // info: { // isHidden: false, // type: 'error', // message: 'Failed to upload', // details: 'Error description' // } console.log(`${info.message} ${info.details}`); }); ``` #### `info-hidden` Fired when “info” message should be hidden in the UI. See [`info-visible`](#info-visible). #### `cancel-all` Fired when `cancelAll()` is called, all uploads are canceled, files removed and progress is reset. #### `restriction-failed` Fired when a file violates certain restrictions when added. This event is providing another choice for those who want to customize the behavior of file upload restrictions. ```js uppy.on('restriction-failed', (file, error) => { // do some customized logic like showing system notice to users }); ``` ## `new BasePlugin(uppy, options?)` The initial building block for a plugin. `BasePlugin` does not contain DOM rendering so it can be used for plugins without an user interface. :::info See [`UIPlugin`][] for the extended version with Preact rendering for interfaces. ::: :::info Checkout the [building plugins](/docs/guides/building-plugins) guide. ::: :::note If you don’t use any UI plugins, any modern bundler should be able to tree-shake Preact code away. If you are not using a bundler that supports tree-shaking, it’s also possible to import `BasePlugin` like this: `import BasePlugin from '@uppy/core/lib/BasePlugin.js`. ::: ### Options The options passed to `BasePlugin` are all you options you wish to support in your plugin. You should pass the options to `super` in your plugin class: ```js class MyPlugin extends BasePlugin { constructor(uppy, opts) { super(uppy, opts); } } ``` ### Methods #### `setOptions(options)` Options passed during initialization can also be altered dynamically with `setOptions`. #### `getPluginState()` Retrieves the plugin state from the `Uppy` class. Uppy keeps a `plugins` object in state in which each key is the plugin’s `id`, and the value its state. #### `setPluginState()` Set the plugin state in the `Uppy` class. Uppy keeps a `plugins` object in state in which each key is the plugin’s `id`, and the value its state. #### `install()` The `install` method is ran once, when the plugin is added to Uppy with `.use()`. Use this to initialize the plugin. For example, if you are creating a pre-processor (such as [@uppy/compressor](/docs/compressor)) you must add it: ```js install () { this.uppy.addPreProcessor(this.prepareUpload) } ``` Another common thing to do when creating a [UI plugin](#new-uipluginuppy-options) is to [`mount`](#mounttarget) it to the DOM: ```js install () { const { target } = this.opts if (target) { this.mount(target, this) } } ``` #### `uninstall()` The `uninstall` method is ran once, when the plugin is removed from Uppy. This happens when `.close()` is called or when the plugin is destroyed in a framework integration. Use this to clean things up. For instance when creating a pre-processor, uploader, or post-processor to remove it: ```js uninstall () { this.uppy.removePreProcessor(this.prepareUpload) } ``` When creating a [UI plugin](#new-uipluginuppy-options) you should [`unmount`](#unmount) it from the DOM: ```js uninstall () { this.unmount() } ``` #### `i18nInit` Call `this.i18nInit()` once in the constructor of your plugin class to initialize [internationalisation](/docs/locales). #### `addTarget` You can use this method to make your plugin a `target` for other plugins. This is what `@uppy/dashboard` uses to add other plugins to its UI. #### `update` Called on each state update. You will rarely need to use this, unless if you want to build a UI plugin using something other than Preact. #### `afterUpdate` Called after every state update with a debounce, after everything has mounted. ## `new UIPlugin(uppy, options?)` `UIPlugin` extends [`BasePlugin`][] to add rendering with [Preact](https://preactjs.com/). Use this when you want to create an user interface or an addition to one, such as [Dashboard][]. :::info See [`BasePlugin`][] for the initial building block for all plugins. ::: :::info Checkout the [building plugins](/docs/guides/building-plugins) guide. ::: ### Options The options passed to `UIPlugin` are all you options you wish to support in your plugin. You should pass the options to `super` in your plugin class: ```js class MyPlugin extends UIPlugin { constructor(uppy, opts) { super(uppy, opts); } } ``` In turn these are also passed to the underlying `BasePlugin`. ### Methods All the methods from [`BasePlugin`][] are also inherited into `UIPlugin`. #### `mount(target)` Mount this plugin to the `target` element. `target` can be a CSS query selector, a DOM element, or another Plugin. If `target` is a Plugin, the source (current) plugin will register with the target plugin, and the latter can decide how and where to render the source plugin. #### `onMount()` Called after Preact has rendered the components of the plugin. #### `unmount` Removing the plugin from the DOM. You generally don’t need to override it but you should call it from [`uninstall`](#uninstall). The default is: ```js unmount () { if (this.isTargetDOMEl) { this.el?.remove() } this.onUnmount() } ``` #### `onUnmount()` Called after the elements have been removed from the DOM. Can be used to do some clean up or other side-effects. #### `render()` Render the UI of the plugin. Uppy uses [Preact](https://preactjs.com) as its view engine, so `render()` should return a Preact element. `render` is automatically called by Uppy on each state change. #### `update(state)` Called on each state update. You will rarely need to use this, unless if you want to build a UI plugin using something other than Preact. ## `debugLogger()` Logger with extra debug and warning logs for during development. ```js import { Uppy, debugLogger } from '@uppy/core'; new Uppy({ logger: debugLogger }); ``` :::info You can also enable this logger by setting [`debug`](#debug) to `true`. ::: The default value of [`logger`](#logger) is `justErrorsLogger`, which looks like this: ```js // Swallow all logs, except errors. // default if logger is not set or debug: false const justErrorsLogger = { debug: () => {}, warn: () => {}, error: (...args) => console.error(`[Uppy] [${getTimeStamp()}]`, ...args), }; ``` `debugLogger` sends extra debugging and warning logs which could be helpful during development: ```js // Print logs to console with namespace + timestamp, // set by logger: Uppy.debugLogger or debug: true const debugLogger = { debug: (...args) => console.debug(`[Uppy] [${getTimeStamp()}]`, ...args), warn: (...args) => console.warn(`[Uppy] [${getTimeStamp()}]`, ...args), error: (...args) => console.error(`[Uppy] [${getTimeStamp()}]`, ...args), }; ``` ## Frequently asked questions ### How do I allow duplicate files? You can allow all files, even duplicate files, with [`onBeforeFileAdded`](#onbeforefileaddedfile-files). This will override the file if it has not been uploaded. If you upload a duplicate file again it depends on your upload plugin and backend how it is handled. ```js const uppy = new Uppy({ // ... onBeforeFileAdded: () => true, ``` [dashboard]: /docs/dashboard [`baseplugin`]: #new-basepluginuppy-options [`uiplugin`]: #new-uipluginuppy-options --- Source: https://uppy.io/docs # Uppy documentation Uppy is a modular JavaScript file uploader for web browsers. Start with the [quick start](/docs/quick-start), then use these guides to assemble the upload experience your application needs: - [Choose an uploader](/docs/guides/choosing-uploader) - [Build a full-featured Dashboard](/docs/dashboard) - [Integrate React](/docs/react), [Vue](/docs/vue), [Svelte](/docs/svelte), or [Angular](/docs/angular) - [Add remote sources through Companion](/docs/companion) - [Browse working examples](/examples) For instructions on linting or previewing these docs locally, see the [contributing guide](https://github.com/transloadit/uppy/blob/main/.github/CONTRIBUTING.md#uppyio-website). --- Source: https://uppy.io/docs/vue # Vue [Vue][] components for the Uppy UI plugins. ## Install **NPM** ```shell npm install @uppy/vue ``` **Yarn** ```shell yarn add @uppy/vue ``` :::note You also need to install the UI plugin you want to use. For instance, `@uppy/dashboard`. ::: To send files to Transloadit, follow the canonical [Vue + Uppy + Transloadit guide](/docs/guides/uppy-transloadit#vue). It includes the required server-side signing boundary. ## Use Uppy offers three ways to build user interfaces: 1. **Pre-composed, plug-and-play components.** Mainly ``. The downside is that you can’t customize the UI. 2. **Headless components.** Smaller components, easier to override the styles or compose them together with your own components. 3. **Hooks.** Attach our logic to your own components, no restrictions, create a tailor-made UI. ### Components Pre-composed, plug-and-play components: - `` renders [`@uppy/dashboard`](/docs/dashboard) - `` renders [`@uppy/dashboard`](/docs/dashboard) as a modal - `` renders [`@uppy/status-bar`](/docs/status-bar) :::note `` and `` were removed in Uppy 5.0. Use the headless [``](#dropzone-) component or the [`useDropzone`](#usedropzoneoptions) hook instead. The [`@uppy/drag-drop`](/docs/drag-drop) plugin itself is still supported for setups without a framework. ::: ### Headless Components :::tip Play around with the Vue headless components in StackBlitz ::: :::note All components must be placed within a `UppyContextProvider`. ::: Uppy’s headless components are smaller and more flexible. All components must be placed within a `UppyContextProvider`. They come styled as well but you can override the styles with data attributes, for example with `UploadButton`: ```css button[data-uppy-element='upload-button'][data-state='uploading'] { background-color: lightblue; } ``` #### `UppyContextProvider` Provides Uppy context to child components and manages global upload status/progress. ```vue ``` **Context Value**: ```typescript { uppy: Uppy | undefined; status: 'init' | 'ready' | 'uploading' | 'paused' | 'error' | 'complete'; progress: number; } ``` #### `` **Attributes** - `data-uppy-element="upload-button"` - `data-state="init" | "uploading" | "paused" | "error" | "complete"` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/vue for the full page.)* #### `` Component for displaying image thumbnails and/or SVG icons. **Props**: - `file: UppyFile` - `width?: string` - `height?: string` - `images?: boolean` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/vue for the full page.)* #### `` Common icons, such as a webcam, device, Dropbox, Google Drive, OneDrive, etc. **Props**: - `provider`: `'device' | 'camera' | 'screen-capture' | 'audio' | 'dropbox' | 'facebook' | 'onedrive' | 'googlephotos' | 'googledrive'` - `fill?: string` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/vue for the full page.)* #### `` Component for displaying a list view of selected files. **Props**: - `editFile?: (file: UppyFile) => void` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/vue for the full page.)* #### `` Grid layout component for displaying files in a grid format. **Props**: - `editFile?: (file: UppyFile) => void` - `columns?: number` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/vue for the full page.)* #### `` Drag-and-drop zone component for file uploads. **Props**: - `width?: string` - `height?: string` - `note?: string` - `noClick?: boolean` *(A rendered component is omitted from the Markdown version — see https://uppy.io/docs/vue for the full page.)* ### Hooks :::tip Play around with the Vue headless hooks in StackBlitz ::: :::note All hooks must be used within a `UppyContextProvider`. ::: #### `useDropzone(options?)` Creates a dropzone for drag-and-drop file uploads using Uppy. **Arguments**: - `noClick?: boolean` - `onDragOver?: (event: Event) => void` - `onDragEnter?: (event: Event) => void` - `onDragLeave?: (event: Event) => void` - `onDrop?: (files: File[]) => void` - `onFileInputChange?: (files: File[]) => void` **Returns**: - `getRootProps: Function` - `getInputProps: Function` #### `useFileInput(props?)` Creates a file input for programmatic file selection using Uppy. **Arguments**: - `multiple?: boolean` - `accept?: string` **Returns**: - `getInputProps: Function` - `getButtonProps: Function` #### `useRemoteSource(sourceId)` Manages remote source connections (cloud storage providers). **Arguments**: - `sourceId: 'Box' | 'Dropbox' | 'Facebook' | 'GoogleDrive' | 'OneDrive' | 'Unsplash' | 'Url' | 'Zoom'` **Returns**: ```typescript { state: { authenticated: boolean | undefined didFirstRender: boolean searchString: string loading: boolean | string partialTree: PartialTree currentFolderId: PartialTreeId username: string | null breadcrumbs: PartialTreeFolder[] selectedAmount: number error: string | null } login: Function logout: Function open: Function checkbox: Function done: Function cancel: Function } ``` #### `useWebcam({ onSubmit })` Manages webcam functionality for capturing photos/videos. **Arguments**: - `onSubmit: () => void` **Returns**: ```typescript { state: { hasCamera: boolean cameraReady: boolean cameraError: null | Error recordingLengthSeconds: number videoSources: MediaDeviceInfo[] currentDeviceId: string | MediaStreamTrack | null | undefined recordedVideo: null | string isRecording: boolean status: 'init' | 'ready' | 'recording' | 'captured' | 'error' } stop: Function start: Function getVideoProps: Function getSnapshotButtonProps: Function getRecordButtonProps: Function getStopRecordingButtonProps: Function getSubmitButtonProps: Function getDiscardButtonProps: Function } ``` #### `useScreenCapture({ onSubmit })` Manages screen capture functionality for capturing screen image / video. **Arguments**: - `onSubmit: () => void` **Returns**: ```typescript { state: { streamActive: boolean; audioStreamActive: boolean; recording: boolean; recordedVideo: string | null; screenRecError: Error | null; capturedScreenshotUrl: string | null; status: 'init' | 'ready' | 'recording' | 'captured' | 'error'; } stop: Function; start: Function; getVideoProps: Function; getScreenshotButtonProps: Function; getRecordButtonProps: Function; getStopRecordingButtonProps: Function; getSubmitButtonProps: Function; getDiscardButtonProps: Function; } ``` [vue]: https://vuejs.org --- Source: https://uppy.io/docs/webcam # Webcam The `@uppy/webcam` plugin lets you take photos and record videos with a built-in camera on desktop and mobile devices. :::tip [Try out the live example](/examples) or take it for a spin in [StackBlitz](https://stackblitz.com/edit/vitejs-vite-zaqyaf?file=main.js). ::: ## When should I use it? When you want your users to able to use their camera. This plugin is published separately but made specifically for the [Dashboard](/docs/dashboard). You can technically use it without it, but it’s not officially supported. ## Install **NPM** ```shell npm install @uppy/webcam ``` **Yarn** ```shell yarn add @uppy/webcam ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use :::note To use the Webcam plugin in Chrome, [your site must be served over https](https://developers.google.com/web/updates/2015/10/chrome-47-webrtc#public_service_announcements). This restriction does not apply on `localhost`, so you don’t have to jump through many hoops during development. ::: ```js {3,7,11} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import Webcam from '@uppy/webcam'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; import '@uppy/webcam/css/style.min.css'; new Uppy().use(Dashboard, { inline: true, target: 'body' }).use(Webcam); ``` ## API ### Options #### `id` A unique identifier for this plugin (`string`, default: `'Webcam'`). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `countdown` When taking a picture: the amount of seconds to wait before actually taking a snapshot (`boolean`, default: `false`). If set to `false` or 0, the snapshot is taken right away. This also shows a `Smile!` message through the [Informer](/docs/informer) before the picture is taken. #### `onBeforeSnapshot` A hook function to call before a snapshot is taken (`Function`, default: `Promise.resolve`). The Webcam plugin will wait for the returned Promise to resolve before taking the snapshot. This can be used to carry out variations on the `countdown` option for example. #### `modes` The types of recording modes to allow (`Array`, default: `[]`). - `video-audio` - Record a video file, capturing both audio and video. - `video-only` - Record a video file with the webcam, but don’t record audio. - `audio-only` - Record an audio file with the user’s microphone. - `picture` - Take a picture with the webcam. By default, all modes are allowed, and the Webcam plugin will show controls for recording video as well as taking pictures. #### `mirror` Configures whether to mirror preview image from the camera (`boolean`, default: `true`). This option is useful when taking a selfie with a front camera: when you wave your right hand, you will see your hand on the right on the preview screen, like in the mirror. But when you actually take a picture, it will not be mirrored. This is how smartphone selfie cameras behave. #### `videoConstraints` Configure the [`MediaTrackConstraints`][] (`Object`, default: `{}`). You can specify acceptable ranges for the resolution of the video stream using the [`aspectRatio`][], [`width`][], and [`height`][] properties. Each property takes an object with `{ min, ideal, max }` properties. For example, use `width: { min: 720, max: 1920, ideal: 1920 }` to allow any width between 720 and 1920 pixels wide, while preferring the highest resolution. Devices sometimes have several cameras, front and back, for example. [`facingMode`][] lets you specify which should be used: - `user`: The video source is facing toward the user; this includes, for example, the front-facing camera on a smartphone. - `environment`: The video source is facing away from the user, thereby viewing their environment. This is the back camera on a smartphone. - `left`: The video source is facing toward the user but to their left, such as a camera aimed toward the user but over their left shoulder. - `right`: The video source is facing toward the user but to their right, such as a camera aimed toward the user but over their right shoulder. For a full list of available properties, check out MDN documentation for [`MediaTrackConstraints`][]. [`mediatrackconstraints`]: https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#Properties_of_video_tracks [`aspectratio`]: https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/aspectRatio [`width`]: https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/width [`height`]: https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/height [`facingmode`]: https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/facingMode #### `showVideoSourceDropdown` Configures whether to show a dropdown which enables to choose the video device to use (`boolean`, default: `false`). This option will have priority over `facingMode` if enabled. #### `showRecordingLength` Configures whether to show the length of the recording while the recording is in progress (`boolean`, default: `false`). #### `preferredVideoMimeType` Set the preferred mime type for video recordings, for example `'video/webm'` (`string`, default: `null`). If the browser supports the given mime type, the video will be recorded in this format. If the browser does not support it, it will use the browser default. If no preferred video mime type is given, the Webcam plugin will prefer types listed in the [`allowedFileTypes` restriction](/docs/uppy/#restrictions), if any. #### `preferredImageMimeType` Set the preferred mime type for images, for example `'image/png'` (`string`, default: `image/jpeg`). If the browser supports rendering the given mime type, the image will be stored in this format. Else `image/jpeg` is used by default. If no preferred image mime type is given, the Webcam plugin will prefer types listed in the [`allowedFileTypes` restriction](/docs/uppy/#restrictions), if any. #### `mobileNativeCamera` Replaces Uppy’s custom camera UI on mobile and tablet with the native device camera (`Function: boolean` or `boolean`, default: `isMobile()`). This will show the “Take Picture” and / or “Record Video” buttons, which ones show depends on the [`modes`](#modes) option. You can set a boolean to forcefully enable / disable this feature, or a function which returns a boolean. By default we use the [`is-mobile`](https://github.com/juliangruber/is-mobile) package. #### `locale` ```js export default { strings: { pluginNameCamera: 'Camera', noCameraTitle: 'Camera Not Available', noCameraDescription: 'In order to take pictures or record video, please connect a camera device', recordingStoppedMaxSize: 'Recording stopped because the file size is about to exceed the limit', submitRecordedFile: 'Submit recorded file', discardRecordedFile: 'Discard recorded file', // Shown before a picture is taken when the `countdown` option is set. smile: 'Smile!', // Used as the label for the button that takes a picture. // This is not visibly rendered but is picked up by screen readers. takePicture: 'Take a picture', // Used as the label for the button that starts a video recording. // This is not visibly rendered but is picked up by screen readers. startRecording: 'Begin video recording', // Used as the label for the button that stops a video recording. // This is not visibly rendered but is picked up by screen readers. stopRecording: 'Stop video recording', // Used as the label for the recording length counter. See the showRecordingLength option. // This is not visibly rendered but is picked up by screen readers. recordingLength: 'Recording length %{recording_length}', // Title on the “allow access” screen allowAccessTitle: 'Please allow access to your camera', // Description on the “allow access” screen allowAccessDescription: 'In order to take pictures or record video with your camera, please allow camera access for this site.', }, }; ``` --- Source: https://uppy.io/docs/xhr-upload # XHR The `@uppy/xhr-upload` plugin is for regular uploads to a HTTP server. ## When should I use it? :::tip Not sure which uploader is best for you? Read “[Choosing the uploader you need](/docs/guides/choosing-uploader)”. ::: When you have an existing HTTP server and you don’t need Transloadit services or want to run a [tus][] server. Note that it’s still possible to use [tus][] without running an extra server by integrating tus into your existing one. For instance, if you have a Node.js server (or server-side framework like Next.js) you could integrate [tus-node-server][]. ## Install **NPM** ```shell npm install @uppy/xhr-upload ``` **Yarn** ```shell yarn add @uppy/xhr-upload ``` **CDN** > **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use A quick overview of the complete API. ```js {10} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import XHR from '@uppy/xhr-upload'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: 'body' }) .use(XHR, { endpoint: 'https://your-domain.com/upload' }); ``` ## API ### Options #### `id` A unique identifier for this plugin (`string`, default: `'XHRUpload'`). #### `endpoint` URL of the HTTP server (`string` or `function`, default: `null`). The endpoint can also be derived from file data by providing a function. ```js const endpoint = (fileOrBundle) => { const signedUploadUrl = await createSignedUpload(fileOrBundle) return signedUploadUrl; }; ``` #### `method` Configures which HTTP method to use for the upload (`string`, default: `'POST'`). #### `formData` Configures whether to use a multipart form upload, using [FormData][] (`boolean`, default: `true`). This works similarly to using a `` element with an `` for uploads. When set to `true`, file metadata is also sent to the endpoint as separate form fields. When set to `false`, only the file contents are sent. #### `fieldName` When [`formData`](#formdata) is set to true, this is used as the form field name for the file to be uploaded. It defaults to `'files[]'` if `bundle` option is set to `true`, otherwise it defaults to `'file'`. #### `allowedMetaFields` Pass an array of field names to limit the metadata fields that will be added to upload. - Set it to `false` to not send any fields (or an empty array). - Set it to `['name']` to only send the `name` field. - Set it to `true` (the default) to send _all_ metadata fields. If the [`formData`](#formdata) option is set to false, `metaFields` is ignored. #### `headers` An object containing HTTP headers to use for the upload request. Keys are header names, values are header values. ```js const headers = { authorization: `Bearer ${window.getCurrentUserToken()}`, }; ``` Header values can also be derived from file data by providing a function. The function receives an [Uppy file][] and must return an object where the keys are header names, and values are header values. ```js const headers = (file) => { return { authorization: `Bearer ${window.getCurrentUserToken()}`, expires: file.meta.expires, }; }; ``` :::note The function syntax is not available when [`bundle`](#bundle) is set to `true`. ::: :::note Failed requests are retried with the same headers. If you want to change the headers on retry, [such as refreshing an auth token](#how-can-i-refresh-auth-tokens-after-they-expire), you can use [`onBeforeRequest`](#onbeforerequest). ::: #### `bundle` Send all files in a single multipart request (`boolean`, default: `false`). All files will be appended to the provided `fieldName` field in the request. :::caution When `bundle` is set to `true`: - [`formData`](#formdata) must also be set to `true`. - Uppy won’t be able to bundle remote files (such as Google Drive) and will throw an error in this case. - Only [global uppy metadata](/docs/uppy/#meta) is sent to the endpoint. Individual per-file metadata is ignored. ::: To upload files on different fields, use [`uppy.setFileState()`](/docs/uppy/#setfilestatefileid-state) to set the `xhrUpload.fieldName` property on the file: ```js uppy.setFileState(fileID, { xhrUpload: { fieldName: 'pic0' }, }); ``` #### `timeout: 30 * 1000` Abort the connection if no upload progress events have been received for this milliseconds amount (`number`, default: `30_000`). Note that unlike the [`XMLHttpRequest.timeout`][xhr.timeout] property, this is a timer between progress events: the total upload can take longer than this value. Set to `0` to disable this check. #### `limit` The maximum amount of files to upload in parallel (`number`, default: `5`). #### `responseType` The response type expected from the server, determining how the `xhr.response` property should be filled (`string`, default: `'text'`). The `xhr.response` property can be accessed in a custom [`getResponseData()`](#getresponsedata) callback. This option sets the [`XMLHttpRequest.responseType`][xhr.responsetype] property. Only `''`, `'text'`, `'arraybuffer'`, `'blob'` and `'document'` are widely supported by browsers, so it’s recommended to use one of those. #### `withCredentials` Indicates whether cross-site Access-Control requests should be made using credentials (`boolean`, default: `false`). #### `onBeforeRequest` An optional function that will be called before a HTTP request is sent out (`(xhr: XMLHttpRequest, retryCount: number, files: UppyFile[]) => void | Promise`). The third argument, `files`, is an array of all Uppy files when `bundle` is `true`. When `false`, it only contains one file. #### `shouldRetry` An optional function called once an error appears and before retrying (`(xhr: XMLHttpRequesT) => boolean`). The amount of retries is 3, even if you continue to return `true`. The default behavior uses [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) with a maximum of 3 retries. #### `onAfterResponse` An optional function that will be called after a HTTP response has been received (`(xhr: XMLHttpRequest, retryCount: number) => void | Promise`). #### `locale: {}` ```js export default { strings: { // Shown in the Informer if an upload is being canceled because it stalled for too long. timedOut: 'Upload stalled for %{seconds} seconds, aborting.', }, }; ``` #### `getResponseData` An optional function to turn your non-JSON response into JSON with a `url` property pointing to the uploaded file (`(xhr: XMLHttpRequest) => { url: string }`). You can also return properties other than `url` and they will end up in `file.response.body`. If you do, make sure to set the `Body` generic on `Uppy` to make it typesafe when using TS. ## Frequently Asked Questions ### How can I refresh auth tokens after they expire? ```js import Uppy from '@uppy/core'; import XHR from '@uppy/xhr-upload'; let token = null; async function getAuthToken() { const res = await fetch('/auth/token'); const json = await res.json(); return json.token; } new Uppy().use(XHR, { endpoint: '', // Called again for every retry too. async onBeforeRequest(xhr) { if (!token) { token = await getAuthToken(); } xhr.setRequestHeader('Authorization', `Bearer ${token}`); }, async onAfterResponse(xhr) { if (xhr.status === 401) { token = await getAuthToken(); } }, }); ``` ### How to send along meta data with the upload? When using XHRUpload with [`formData: true`](#formdata), file metadata is sent along with each upload request. You can set metadata for a file using [`uppy.setFileMeta(fileID, data)`](/docs/uppy/#setfilemetafileid-data), or for all files simultaneously using [`uppy.setMeta(data)`](/docs/uppy/#setmetadata). It may be useful to set metadata depending on some file properties, such as the size. You can use the [`file-added`](/docs/uppy/#file-added) event and the [`uppy.setFileMeta(fileID, data)`](/docs/uppy/#setfilemetafileid-data) method to do this: ```js uppy.on('file-added', (file) => { uppy.setFileMeta(file.id, { size: file.size, }); }); ``` Now, a form field named `size` will be sent along to the [`endpoint`](#endpoint) once the upload starts. By default, all metadata is sent, including Uppy’s default `name` and `type` metadata. If you do not want the `name` and `type` metadata properties to be sent to your upload endpoint, you can use the [`allowedMetaFields`](#allowedmetafields) option to restrict the field names that should be sent. ```js uppy.use(XHRUpload, { // Only send our own `size` metadata field. allowedMetaFields: ['size'], }); ``` ### How to upload to a PHP server? The XHRUpload plugin works similarly to a `` upload. You can use the `$_FILES` variable on the server to work with uploaded files. See the PHP documentation on [Handling file uploads][php.file-upload]. The default form field for file uploads is `files[]`, which means you have to access the `$_FILES` array as described in [Uploading many files][php.multiple]: ```php **Caution:** this CDN bundle contains most Uppy plugins, so it is not > recommended for production. It is useful to get started quickly. ```html
``` ## Use Using Zoom requires setup in both Uppy and Companion. ### Use in Uppy ```js {10-13} showLineNumbers import Uppy from '@uppy/core'; import Dashboard from '@uppy/dashboard'; import Zoom from '@uppy/zoom'; import '@uppy/core/css/style.min.css'; import '@uppy/dashboard/css/style.min.css'; new Uppy() .use(Dashboard, { inline: true, target: '#dashboard' }) .use(Zoom, { companionUrl: 'https://your-companion.com' }); ``` ### Use with Transloadit ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Zoom from '@uppy/zoom'; uppy.use(Zoom, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, }); ``` You may also hit rate limits, because the OAuth application is shared between everyone using Transloadit. To solve that, you can use your own OAuth keys with Transloadit’s hosted Companion servers by using Transloadit Template Credentials. [Create a Template Credential][template-credentials] on the Transloadit site. Select “Companion OAuth” for the service, and enter the key and secret for the provider you want to use. Then you can pass the name of the new credentials to that provider: ```js import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit'; import Zoom from '@uppy/zoom'; uppy.use(Zoom, { companionUrl: COMPANION_URL, companionAllowedHosts: COMPANION_ALLOWED_HOSTS, companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'my_companion_dropbox_creds', }, }); ``` ### Use in Companion To sign up for API keys, go through the following steps: 1. Sign up on [Zoom Marketplace](https://marketplace.zoom.us) 2. Go to [https://marketplace.zoom.us](https://marketplace.zoom.us). There will be a dropdown in the header called “Develop”. From that dropdown, select “Build app”. 3. In the “Basic Information” tab, Zoom shows your new “Client ID” and “Client Secret” - copy them. With the standalone Companion server, specify environment variables: ```shell export COMPANION_ZOOM_KEY="Zoom API key" export COMPANION_ZOOM_SECRET="Zoom API secret" ``` When using the Companion Node.js API, configure these options: ```js companion.app({ providerOptions: { zoom: { key: 'Zoom API key', secret: 'Zoom API secret', }, }, }); ``` 4. In the “Basic Information” tab, set “OAuth Redirect URL” input field to: ``` https://$YOUR_COMPANION_HOST_NAME/zoom/redirect ``` If you are using Transloadit hosted Companion: ``` https://api2.transloadit.com/companion/zoom/redirect ``` 5. In the “Scopes” tab, add “cloud_recording:read:list_user_recordings” and “user:read:user” scopes. If Zoom asks for further permissions when you interact with your Zoom integration - add those too. ## API ### Options #### `id` A unique identifier for this plugin (`string`, default is a unique ID for each plugin). #### `title` Title / name shown in the UI, such as Dashboard tabs (`string`, default is the name of the plugin). #### `target` DOM element, CSS selector, or plugin to place the drag and drop area into (`string`, `Element`, `Function`, or `UIPlugin`, default: [`Dashboard`](/docs/dashboard)). #### `companionUrl` URL to a [Companion](/docs/companion) instance (`string`, default: `null`). For Transloadit-hosted Companion use the `COMPANION_URL` constant exported by `@uppy/transloadit`, which is `https://api2.transloadit.com/companion`. Do not use a regional hostname such as `api2-eu-west-1.transloadit.com`: the OAuth flow then starts on one host and returns to another, and login fails with “Cannot find state in session”. #### `companionHeaders` Custom headers that should be sent along to [Companion](/docs/companion) on every request (`Object`, default: `{}`). #### `companionAllowedHosts` The valid and authorised URL(s) from which OAuth responses should be accepted (`string` or `RegExp` or `Array`). This option is useful when you have your [Companion](/docs/companion) running on several hosts. Otherwise, the default value should do fine, which uses the origin of `companionUrl`. This value can be a `string`, a `RegExp` pattern, or an `Array` of these. Strings are evaluated as regular expressions too and will be wrapped in a RegExp like so: ```js new RegExp(`^${value}$`); ``` **Important:** You must escape regex characters like `.`, or you might open your app up to security vulnerabilities. - Example correct strings - `'^(?:.*\\.)?example\.com$'` matches `example.com` and all of its subdomains. - `'https://example\.com'` matches `https://example.com` only. - Example vulnerability: `'https://www.example.com'` would allow an attacker with the domain `wwwxexample.com` to forge and inject a fraudulent token into Uppy. #### `companionKeysParams` Only applies to plugins that sign in through Companion (Google Drive, Dropbox, Box, OneDrive, …). The Google Drive Picker and Google Photos Picker ignore it; they authenticate directly with Google. Google Drive Picker uses its own `clientId`, `apiKey` and `appId`, while Google Photos Picker uses its own `clientId`. Use your own OAuth app with Transloadit-hosted Companion instead of Transloadit’s shared one (`Object`, default: `undefined`). It has two fields: - `key`: your Transloadit API key. - `credentialsName`: the name of a “Companion OAuth” credential you created in the Transloadit console, which holds the provider’s OAuth key and secret. ```js companionKeysParams: { key: 'YOUR_TRANSLOADIT_API_KEY', credentialsName: 'google_drive_own', } ``` Before the login popup opens, the plugin sends these values to Companion to obtain a pre-auth token, and Companion fetches the OAuth key and secret from Transloadit when the flow starts. The values are also sent along with every later request in a `uppy-credentials-params` header. Companion does not validate the credential name up front, so a wrong name only fails when a user tries to sign in. On Transloadit-hosted Companion this option is required for Google Drive, see [Google Drive: Use with Transloadit](/docs/google-drive#use-with-transloadit). #### `companionCookiesRule` This option correlates to the [RequestCredentials value](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials) (`string`, default: `'same-origin'`). This tells the plugin whether to send cookies to [Companion](/docs/companion). #### `locale` An object with `strings` property containing additional i18n strings. The key is the i18n key and the value is the English string. Example: ```js { strings: { someKey: 'Some English string', }, } ``` #### `storage` A custom storage to be used for the plugin’s persistent data. Type `AsyncStore`, default is `LocalStorage`. [template-credentials]: https://transloadit.com/docs/topics/template-credentials/