Flag of Ukraine   We stand with the brave people of Ukraine. Stop the war. Find out how you can help.

Uppy 0.21: End to End Tests, Accessibility, Additional Security for Uppy Server

Hi all! We’ve been busy with Halloween, but also another release, so here is Uppy 0.21! This one improves accessibility, features new end-to-end tests and improved security in Uppy Server.


One of the goals we’ve set out to achieve with Uppy was to make an accessibe file upload widget, and in this release we’ve achieved some more progress in this area:

  • Dashboard modal dialog now handles focus better (it’s trapped inside the modal while open);
  • First button is in focus right after the modal dialog is open;
  • More (aria-)labels have been added;
  • Files from remote providers are now selectable with a keyboard.

We plan to continue gradually improving in the accessibility area.

See #414 PR for details.

Returning { successful, failed } from uppy.upload()

⚠️ Breaking change

uppy.upload() promise now resolves to a result object with two arrays of files: { successful, failed }. This lets you handle succesful and failed uploads in one go:

uppy.upload().then((result) => {
  console.info('Successful uploads:', result.successful)
  if (result.failed.length > 0) {
    result.failed.forEach((file) => {

// or

uppy.on('core:complete', ({ successful, failed }) => {
  if (failed.length === 0) {
    console.log('UPLOAD SUCCESSFUL!!!')
  } else {
    console.warn('UPLOAD FAILED!!!')
  console.log('successful files:', successful)
  console.log('failed files:', failed)

See uppy.upload() and core:complete in docs, as well as #404 PR for more details.

End to end tests

We’ve refactored end to end tests to use Webdriver.io, and for the occasion added tests for Edge, Safari, Android and iOS. Now tests on Travis and Sauce Labs (thanks for the open source tier!) run smoothly and it’s easier to alter them or write new ones.

More secure Uppy Server

We made sure access tokens from third-party providers, such as Google Drive or Instagram, are not stored on the server with Uppy Server, and kept in your browser instead. Then, when you want to pick a file from your Instagram, the token is used to make a request to Uppy Server, which is in turn used by Uppy Server to communicate with Instagram.

Data validation is also now done during intiation of an upload, to prevent corrupt data from triggering funny behaviours on the server. :)

And, while we were at this, we also made sure all sensitive data is masked in request logs.

Migration to Dropbox v2 API

Since the deprecation of Dropbox v1 API, uppy/uppy-server have now been updated to use the v2 API. It is implemented to work closely as its previous implementation so there should be no worries.

Custom plugin id

Up until now you could only use a plugin once with an Uppy instance. Now you can pass custom id for any plugin (though this has to be manually implemented in any new plugin). This allows using, for example, two StatusBars, one inside the Dashboard, and one somewhere on the page, visible even when Dashboard is closed.

Can be used like this:

// one StatusBar comes included in the Dashboard, another will be mounted on the page
.use(Dashboard {...})
.use(StatusBar, { id: 'PageStatusBar', target: 'body' }

See #418 PR for details.

Misc good stuff

  • Migrated Dropbox in Uppy Server to use v2 API.
  • Fixed generating thumbnails for images with transparent background.
  • We are now using tinyify(by our own @goto-bus-stop) for the Uppy bundle to make it smaller and more efficient.
  • Instead of restarting only the file upload itself, start an entirely new upload for retries. Fixes retrying uploads with processing plugins.
  • The S3 plugin now includes XHRUpload. ⚠️ Breaking change: you should remove .use(XHRUpload) when using S3.
  • XHRUpload now includes a timeout opts.timeout = 30000, after which it errors and offers a retry (retry UI supported in Dashboard), see #378 for more.
  • Renamed RestoreFilesGoldenRetriever, and Tus10Tus. ⚠️ Breaking change: please make sure to use the new names when setting up plugins.
  • The Webcam plugin has been refactored. There’s no flash fallback now, it works in modern browsers only, and the Webcam tab won’t appear in the Dashboard if a camera is not supported on the device.

Full Changelog

Here is the full list of changes for version 0.21.0 (and patches 0.20.1, 0.20.2, 0.20.3):

  • accessibility: add tabindex=”0” to buttons and tabs, aria-labels, focus (#414 / @arturi)
  • core: allow setting custom id for plugins to allow a plugin to be used multiple times (#418 / @arturi)
  • core: do not check isPreviewSupported for unknown filetypes (#417 / @sadovnychyi)
  • core: refactor uppy-base (#382 / @goto-bus-stop)
  • core: remove functions from state object (#408 / @goto-bus-stop)
  • core: return { successful, failed } from uppy.upload() (#404 / @goto-bus-stop)
  • core: update state with error messages rather than error objects (#406 / @richardwillars)
  • core: use tinyify for the unpkg bundle. (#371 / @goto-bus-stop)
  • dashboard: Fix pasting files, default image file name, add type to meta, file type refactor (#395 / @arturi)
  • dragdrop: Fix of the .uppy-DragDrop-inner spacing on small screens (#405 / @nqst)
  • react: fix uppy PropType, closes (#416 / @goto-bus-stop)
  • s3: automatically wrap XHRUpload. Users should remove .use(XHRUpload) when using S3. (#408 / @goto-bus-stop)
  • test: refactored end-to-end tests to not use website, switched to Webdriver.io, added tests for Edge, Safari, Android and iOS (#410 / @arturi)
  • tus: Rename Tus10 → Tus (#285 / @goto-bus-stop)
  • uppy-serer: mask sensitive data from request logs (@ifedapoolarewaju)
  • uppy-server: add request body validators (@ifedapoolarewaju)
  • uppy-server: migrate dropbox to use v2 API (#386 / @ifedapoolarewaju)
  • uppy-server: store tokens in user’s browser only (@ifedapoolarewaju)
  • webcam: only show the webcam tab when browser support is available (media recorder API) (#421 / @arturi, @goto-bus-stop)
  • webcam: simplify and refactor webcam plugin (modern browser APIs only) (#382 / @goto-bus-stop)
  • xhrupload: set a timeout in the onprogress event handler to detect stale network (#378 / @goto-bus-stop)
  • uppy-server: allow flexible whitelist endpoint protocols (@ifedapoolarewaju)
  • core: Start a completely new upload when retrying. (#390 / @goto-bus-stop)
  • dashboard: Show errors that occurred during processing on the file items. (#391 / @goto-bus-stop)
  • transloadit: Mark files as having errored if their assembly fails. (#392 / @goto-bus-stop)
  • core: Clear file upload progress when an upload starts. (#393 / @goto-bus-stop)
  • tus: Clean up tus.Upload instance and events when an upload starts, finishes, or fails. (#390 / @goto-bus-stop)
  • docs: fix getMetaFromForm documentation (@arturi)
  • core: fix generating thumbnails for images with transparent background (#380 / @goto-bus-stop)
  • transloadit: use Translator class for localised strings (#383 / @goto-bus-stop)
  • goldenretriever: don’t crash when required server-side (#384 / @goto-bus-stop)
  • redux: add plugin for syncing uppy state with a Redux store (#376 / @richardwillars)

The Uppy Team