# My first App

Transloadit is versatile and there are many ways to leverage our API. To pick one happy path for demo purposes, weʼll default to a web browser integration with [Uppy](/docs/sdks/uppy.md)ʼs Transloadit Plugin.

We will create a simple web page where you resize uploaded files to `1500x500` pixels and have them stored in your S3 bucket.

## Our First Template

Please [create a new Template](/c/templates/new/) in your workspace naming it `my-first-template` and and save the following Assembly Instructionsinside of it:

![](/_next/static/media/copy.04p1cju9qekk_.svg?dpl=dpl_2spFSmvDCBLZSSAYXEqsCRsJ4nmu)

```json
{
  ":original": {
    "robot": "/upload/handle"
  },
  "crop_thumbed": {
    "use": ":original",
    "robot": "/image/resize",
    "result": true,
    "width": 1500,
    "height": 500,
    "resize_strategy": "fillcrop"
  },
  "exported": {
    "use": [
      "crop_thumbed",
      ":original"
    ],
    "robot": "/s3/store",
    "credentials": "demo_s3_credentials",
    "url_prefix": "https://demos.transloadit.com/"
  }
}

```

## Explaining the Assembly Instructions

Now, let's take a closer look at the JSON, which contains threeSteps:

1. `:original` invokes [🤖/upload/handle](/docs/robots/upload-handle.md), which will receive any file Uppy throws at it, and then make it available for otherRobots to consume. You could define a file size limit in this Robot among other things.
2. `crop_thumbed` is happy to take those files via `"use": ":original"`. It then invokes[🤖/image/resize](/docs/robots/image-resize.md) with parameters such as`resize_strategy`.
3. `exported` stores both the originally uploaded files and the resized renditions in your S3 bucket with the help of [🤖/s3/store](/docs/robots/s3-store.md). The credentials to S3 are created and stored separately in your account for security purposes. You refer to them by name, replacing `demo_s3_credentials`. [Learn more](/docs/topics/template-credentials.md)

###### Note

If you don't have an S3 bucket (or any other[supported export target](/docs/robots.md#service-file-exporting/)), you could[create one](/docs/faq/how-to-set-up-an-amazon-s3-bucket.md) or leave out the `exported` Step for now. Our prototype will still work, but result files are then hosted with us and removed after 24h.

In our Uppy integration replace `YOUR_TEMPLATE_ID` with the ID of your Template. Add the following to a `test.html` file and then open it in your browser:

![](/_next/static/media/copy.04p1cju9qekk_.svg?dpl=dpl_2spFSmvDCBLZSSAYXEqsCRsJ4nmu)

```html
<!-- This pulls Uppy from our CDN -->
<!-- For smaller self-hosted bundles, install Uppy and plugins manually: -->
<!-- npm i @uppy/core @uppy/dashboard @uppy/remote-sources @uppy/transloadit ... -->
<link
  href="https://releases.transloadit.com/uppy/v4.3.1/uppy.min.css"
  rel="stylesheet"
/>
<button id="browse">Select Files</button>
<script type="module">
  import {
    Uppy,
    Dashboard,
    ImageEditor,
    RemoteSources,
    Transloadit,
  } from 'https://releases.transloadit.com/uppy/v4.3.1/uppy.min.mjs'
  const uppy = new Uppy()
    .use(Transloadit, {
      waitForEncoding: true,
      alwaysRunAssembly: true,
      assemblyOptions: {
        params: {
          template_id: 'YOUR_TEMPLATE_ID',
          // To avoid tampering, use Signature Authentication:
          // https://transloadit.com/docs/api/authentication/
          auth: {
            key: 'YOUR_TRANSLOADIT_KEY',
          },
        },
      },
    })
    .use(Dashboard, { trigger: '#browse' })
    .use(ImageEditor, { target: Dashboard })
    .use(RemoteSources, {
      companionUrl: 'https://api2.transloadit.com/companion',
    })
    .on('complete', ({ transloadit }) => {
      // Due to waitForEncoding:true this is fired after encoding is done.
      // Alternatively, set waitForEncoding to false and provide a notify_url
      console.log(transloadit) // Array of Assembly Statuses
      transloadit.forEach((assembly) => {
        console.log(assembly.results) // Array of all encoding results
      })
    })
    .on('error', (error) => {
      console.error(error)
    })
</script>

```

You'll notice that along with `YOUR_TEMPLATE_ID`, we'll also need to replace `YOUR_TRANSLOADIT_KEY`, the value for which can be obtained[by creating an Auth Key in your account](/c/template-credentials/).

And there you have it! ✨ If you were copy/pasting/replacing along, you now have a working prototype. The results are dumped in your browser's console log, but you can also see[Assemblies](/c/assemblies/) added to your account in real time. If you didn't type along, you can still try it live in this[image resize demo](/demos/image-manipulation/resize-to-twitter-cover-dimensions/).

We're not quite there yet, though. The results are in your S3 bucket and referenced in the console log. But how to get these results to your back-end so that others can enjoy them too? Find out on the [Saving Result Files](/docs/getting-started/saving-conversion-results.md) page.
