Twilio Assets is a static file hosting service that allows developers to quickly upload and serve the files needed to support their applications. With Twilio Assets you can host your files that support web, voice, and messaging applications. Twilio Assets is frequently used to host .mp3
audio files used in TwiML and Studio Flows, to serve images sent through MMS, or to store configuration used by Twilio Functions.
Twilio provides you with three different types of Assets: public, protected, and private. The primary difference between the types is how they are accessed:
If you would like to learn more about Asset visibility, we have a document that goes over the distinctions between public, protected, and private assets in greater detail.
Anyone with the URL to a public asset will be able to access it. Therefore, customers should be thoughtful about what data they include in a public asset.
Asset files are uploaded as is, with all metadata persisted. If your Asset files contain metadata, that will be stored with the file. An example would be EXIF metadata stored with an image. If you are making files available, please note that metadata is persisted and not removed/changed by the Assets product in any way.
Start by opening one of your existing Services, or by creating a new one. Once you're in the Functions Editor UI for your Service there are three points of interest:
Upload a file by clicking Add+ and then Upload File in the resulting menu, which will open up a standard file upload dialogue. Once you've selected a file or files, you'll be presented with options to set the visibility of each Asset, as well as the ability to remove or add other files. Click Upload to begin uploading your selection of files with the desired settings.
While the Asset has been uploaded, it will not be immediately accessible via a URL or in your Functions yet. This will be indicated by the gray circle next to the Asset's name. To deploy the Asset (and the rest of your Service), click the Deploy All button. After a brief period, the deployment will finish, and you should see a green check appear next to all deployed Assets.
In general the URL of one of your Assets can be determined by taking the URL of your Service, for example https://example-1234.twil.io
, and appending the name of your Asset.
In the case of an Asset such as example.json
in that Service, it can be accessed at https://example-1234.twil.io/example.json
.
For a point and click solution, the Functions Editor UI also provides two ways to copy the URL of an Asset to your clipboard:
Public assets are publicly accessible once deployed, and can be used by referencing their URL. For example: given a Service with the URL of https://example-1234.twil.io
and a public Asset named ahoy.mp3
, the Asset will be available at https://example-1234.twil.io/ahoy.mp3
.
The process for determining the URL of a protected Asset is the same as that of a public Asset. However, the Asset will only be accessible from Twilio code such as a Function, Studio Flow, or Flex.
For example, suppose we have an image grumpy.jpg
that's been deployed to https://twilio-assets-1967.twil.io/grumpy.jpg
. We would like to be able to send this image to users as part of an MMS, but have the file be inaccessible in all other cases. If the following code were deployed to a Function in the same Service and executed, the recipient will receive the image of grumpy cat, but anybody else trying to access the file by URL will be returned a 403 Forbidden
error instead.
1exports.handler = (context, event, callback) => {2// Access the NodeJS Helper Library by calling context.getTwilioClient()3const client = context.getTwilioClient();4// Query parameters or values sent in a POST body can be accessed from `event`5const from = event.From || '+15017122661';6const to = event.To || '+15558675310';7const body = event.Body || 'Ahoy, World!';89client.messages10.create({11to,12from,13body,14// You will get a 403 if you try to view this image, but Twilio will15// be able to access it and send it as part of the outgoing MMS16mediaUrl: 'https://twilio-assets-1967.twil.io/grumpy.jpg',17})18.then((message) => {19console.log(`Success! MMS SID: ${message.sid}`);20return callback(null, message.sid);21})22.catch((error) => {23console.error(error);24return callback(error);25});26};
Similarly, suppose you have audio or messaging to include in your Studio Flow, but don't want that audio to be accessible to the entire internet. If the audio were uploaded as protected Asset, you could then reference its URL in the Studio Say/Play widget, and the audio will play for anybody that hits that part of your Flow.
For example, if the audio were a protected Asset deployed at https://twilio-assets-1967.twil.io/sensitive-message.mp3
, it could be referenced in your Studio Flow as shown below:
When Twilio builds your Function for deployment it will bundle any and all Private Assets that you have uploaded. This makes Private Assets perfect for storing sensitive configuration files, templates, and shared code that supports your application.
In order to access a private Asset, you will need to leverage the Runtime.getAssets method and open the file directly using either the open
helper method, or by using helper methods from the fs
module as shown in the following examples.
Example of how to read the contents of a Private Asset
1exports.handler = (context, event, callback) => {2// Access the open helper method for the Asset3const openFile = Runtime.getAssets()['/my_file.txt'].open;45// Open the Private Asset and read the contents.6// Calling open is equivalent to using fs.readFileSync(asset.filePath, 'utf8')7const text = openFile();8console.log('Your file contents: ' + text);910return callback();11};
Example of how to serve an audio file from a Private Asset
1// Load the fs module2const fs = require('fs');34exports.handler = (context, event, callback) => {5// Get the path to the Private Asset6const mp3Path = Runtime.getAssets()['/audio.mp3'].path;78// Read the file into the buffer and get its metadata9const buffer = fs.readFileSync(mp3Path);10const stat = fs.statSync(mp3Path);11// Create a new Response object12const response = new Twilio.Response();13// Send the audio file in the response14response.setBody(buffer);15response.appendHeader('Content-Type', 'audio/mpeg');16response.appendHeader('Content-Length', stat.size);1718return callback(null, response);19};
In some cases, such as when hosting an app with a landing page, you want the root URL of your Service to return an Asset in the browser. For example, you can visit root-asset-5802.twil.io/ which serves static HTML solely via Assets.
To reproduce this behavior, you will need to use one of two special paths for a public Asset for your file (whether it be HTML, an image, or anything else).
You may rename an Asset's path to /
, and that Asset will be served on requests to the root URL of your Service. In the Console UI, it would look like this:
This path applies only to HTML files. Renaming an HTML file's path to /assets/index.html
will cause the Service to return that page on requests to the root URL of your Service. It would look like this in the Console UI:
You can practice this yourself using the following index.html
example code:
1<!DOCTYPE html>2<html lang="en">3<head>4<meta charset="UTF-8" />5<meta name="viewport" content="width=device-width, initial-scale=1.0" />6<meta http-equiv="X-UA-Compatible" content="ie=edge" />7<title>Hello Twilio Serverless!</title>8</head>9<body>10<header><h1>Hello from Twilio Serverless!</h1></header>11<main>12<p>13This page is a public Asset that can be accessed from the root URL of14this Service!15</p>16</main>17<footer>18<p>19Made with 💖 by your friends at20<a href="https://www.twilio.com">Twilio</a>21</p>22</footer>23</body>24</html>
If you want to deploy a root Asset using the Serverless Toolkit instead, you will need to create the /assets/index.html
path within the existing assets/
folder that exists for your project.
The resulting path in your local filesystem will be /assets/assets/index.html
, and the folder hierarchy will be as follows:
1.2├── assets3│ └── assets4│ └── index.html5├── functions6└── package.json
All Builds have limitations on the maximum allowable file size and quantity of each Asset type that can be included:
Asset Type | Maximum Size | Quantity |
---|---|---|
Public | 25 MB | 1000 Assets |
Private | 10 MB | 50 Assets |
Protected | 25 MB | 1000 Assets |
These limits apply only to individual Builds, so Assets used in a Build by a Subaccount won't affect the limits of other Subaccounts or the main Account.
Using Environments further expands your options, as you can create Builds containing different sets of Assets and deploy them to separate Environments.
When using the Serverless API (either directly, via the Helper Libraries, or through the CLI), you can create more Assets and Asset Versions within a Service, for example, to have different Assets in different Environments. However, a particular Build can only include so many Assets, as indicated in the table above.
This flexibility is currently not supported by the Console UI. Every Asset listed in the UI will be included in the deployed Build, and you will be unable to upload Assets in excess of the stated limits.