In an age when data is only a few seconds away, the last thing we want is for our users to waste time waiting. That's why today, using PHP, we're demonstrating how to use Assembly Notifications to interact with Transloadit in Async Mode, so you can spend less time waiting for transcoding Steps to complete.

PHP logo

To set up Transloadit to work asynchronously, we'll need to combine our open source file uploader Uppy, ngrok, a MySQL database, and a little PHP to put it all together. We'll be using vanilla PHP, which will hopefully be easy enough to understand and adapt for people using frameworks such as Laravel, CodeIgniter, Symfony, or CakePHP.

Setting up the website

The first thing we must do is create an Assembly. To keep things simple, we'll use the Robodog Dashboard to upload files to Transloadit.

(Disclaimer: Robodog has now been deprecated and replaced with a Transloadit plugin)

Please create a new folder for the project and then open a new file called index.php.

Next, add our basic HTML skeleton:

  <script src=""></script>
    <div id="dashboard"></div>
      Robodog.dashboard('#dashboard', {
        params: {
          auth: {
            key: 'AUTH_KEY',
          template_id: 'TEMPLATE_ID',
          fields: {
            url: window.location.href,

Setting up the database

Our next step is to create the database. After installing MySQL, launch the MySQL shell terminal (likely just mysql on your system). To get our database up and running, we'll need to execute several commands.

  1. Switch to SQL mode
  1. Connect to the local MySQL server
\connect root@localhost
  1. Create the database
CREATE DATABASE transloadit;
USE transloadit;
  1. Create a table to store information on our Assemblies and an auto-generated timestamp of when we received a pingback
CREATE TABLE assemblies (
  http_code INT(3) NOT NULL,

If you run DESCRIBE assemblies;, you should see a table like so:

| Field     | Type         | Null | Key | Default           | Extra             |
| id        | varchar(100) | NO   | PRI | NULL              |                   |
| ok        | varchar(30)  | NO   |     | NULL              |                   |
| http_code | int          | NO   |     | NULL              |                   |
| timestamp | timestamp    | NO   |     | CURRENT_TIMESTAMP | DEFAULT_GENERATED |

Creating our Template

We're only going to create a basic Template, but feel free to expand on it for your own use case.

  "steps": {
    ":original": {
      "robot": "/upload/handle"
    "resized": {
      "robot": "/image/resize",
      "use": ":original",
      "width": 500,
      "format": "jpeg",
      "resize_strategy": "fit",
      "imagemagick_stack": "v3.0.0"
  "notify_url": "${fields.url}"

Our image is resized to 500px wide before sending a response to the notify_url provided by the field. Our field value has been set to window.location.href since we're using ngrok, which saves us from manually retrieving the URL every time. However, if your PHP will be hosted elsewhere on your site than the Robodog component, you should change this URL.

Make sure to copy the Template ID and paste it into the Robodog component as the template_id.

Starting our web server with ngrok

To send requests to our local server, we'll need to use ngrok (or similar).

To start a local server, we run the following command:

php -S localhost:8000

Then we open the ngrok terminal and run:

ngrok http 8000

Now, if you go to the URL shown in the terminal, you should see the Robodog Dashboard.

Connecting to our database

The very first thing we need to do with PHP is create a link with our MySQL database. Inside of index.php, insert the following code:

$link = mysqli_connect('localhost', 'YOUR_USERNAME', 'YOUR_PASSWORD', 'transloadit');

// Check connection
if ($link === false) {
  die('ERROR: Could not connect. ' . mysqli_connect_error());

Adding data to the database

Of course, when we receive our notification pingback, we'll want to add some of the information to our database. I've cherry-picked a few fields, but you should customize them to your own preferences.

INSERT INTO assemblies (id, ok, http_code)
VALUES ('{$transloadit['assembly_id']}', '{$transloadit['ok']}', '{$transloadit['http_code']}');

We can use the global $_POST variable to populate our JSON when we receive a response.

$transloadit = 'No response data yet! :)';

//Add to database
if (isset($_POST['transloadit'])) {
  $json = $_POST['transloadit'];
  $transloadit = json_decode($json, true);

  // The resulting files can be found inside $transloadit['results'] now.
  // Depending on your integration, you may want to
  // save references to these in your database as well.

  // Attempt insert query execution
  $sql = "INSERT INTO assemblies (id, ok, http_code) VALUES ('{$transloadit['assembly_id']}', '{$transloadit['ok']}', '{$transloadit['http_code']}')";
  if (mysqli_query($link, $sql)) {
    echo 'Records inserted successfully.';
  } else {
    echo "ERROR: Could not able to execute $sql. " . mysqli_error($link);

Retrieving data from the database

To get some feedback and make sure everything is working correctly, let's pull the five most recent Assemblies from our database and display them on our website.

Here's the SQL statement we'll use:

SELECT id,ok,timestamp
FROM assemblies
ORDER BY timestamp DESC

Which we can query and display within our PHP:

// Retrieves five most recent assemblies
$sql = 'SELECT id,ok,timestamp FROM assemblies ORDER BY timestamp DESC LIMIT 5';
$result = mysqli_query($link, $sql);

if ($result->num_rows > 0) {
  // Output the data from each row
  while ($row = $result->fetch_assoc()) {
    echo 'ID: ' .
      $row['id'] .
      ' - OK: ' .
      $row['ok'] .
      ' - TIMESTAMP: ' .
      $row['timestamp'] .
} else {
  echo '0 results';


If you run a few images through the Robodog Dashboard and then refresh the page, you should see a list of Assemblies similar to the one below, indicating that everything is in working order.

ID: 1a8da2d953014362ae7aaf9b1a0a94e1 - OK: ASSEMBLY_COMPLETED - TIMESTAMP: 2021-07-13 12:55:36
ID: ea39c16274d74ff6a6302cf26ce85ee1 - OK: ASSEMBLY_COMPLETED - TIMESTAMP: 2021-07-13 12:39:45
ID: 59bf7ff2c6dc4491a5867125a95d3ee1 - OK: ASSEMBLY_COMPLETED - TIMESTAMP: 2021-07-13 12:39:40
ID: 356250064e1040acb7b3cd70bf1da9e1 - OK: ASSEMBLY_COMPLETED - TIMESTAMP: 2021-07-13 12:39:34
ID: 945161b4de994525aa680614422de5e1 - OK: ASSEMBLY_COMPLETED - TIMESTAMP: 2021-07-13 12:39:28

Finishing up

Hopefully, this blog has piqued your interest in using Transloadit asynchronously, and you've come up with some ideas for how to take it a step further to supercharge your next project ⚡