Edit in GitHubLog an issue

Custom Actions

Use the Custom Actions beta to build integrations directly into Frame.io as programmable UI components. This enables workflows that can be triggered by users within the app, leveraging the same underlying events routing as webhooks. You can create user-triggered single or multi-step forms that come back to Frame.io as another form or a basic response. And when a user clicks a Custom Action on an Asset, Frame.io sends a payload to a URL you provide. The receiving application responds with an HTTP status code to acknowledge receipt, or responds with a custom callback that can render additional UI in Frame.io.

Configure Custom Actions in the Experimental API.


Field nameDescription
Name
The name you choose for your custom action. It will be shown in the menu of available custom actions in Frame.io.
Description
Explain what the action does, for reference (the description won't appear in the Frame.io web app).
Event
Internal event key to help you differentiate between standard webhook events and your own.
URL
Where to deliver events.
Workspace
The Workspace that will use the custom action.

Configure Your Custom Action

When a user selects a Custom Action on an Asset, Frame.io sends a payload to a URL you provide. The receiving application can respond with an HTTP status code to acknowledge receipt, or respond with a custom callback that renders additional UI in Frame.io.

Content Admin permissions are required to create Custom Actions for a Workspace. Ask your admin to modify your permissions if you don't have access.

Payload From Frame.io

When the user clicks your Custom Action, a payload is sent to the URL you set in the URL field. Use this payload to identify:

  • Which Custom Action was clicked
  • Which resource was clicked
  • Which user took the action
  • Which account is associated with the Custom Action
  • Which event type was triggered
  • Which Workspace is associated with the Custom Action
  • Which Project contains the resource on which the Custom action was triggered
Copied to your clipboard
POST /your/url
{
"account_id": "9a44f696-ae69-4e0c-9731-806d27ea46f1",
"action_id": "ecd40785-4485-4f07-9d26-a006ea84efdf",
"interaction_id": "e0a1c945-a8da-480d-92fb-e895cb640a01",
"project":
{
"id": "3dda6833-ec3b-46bd-a7d9-1a77c03a165b"
},
"resource":
{
"id": "f9d5728c-ac1a-4f48-92bb-ea2f9be3c58b",
"type": "file"
},
"type": "two.event",
"user":
{
"id": "50d976e6-27d2-47cb-9388-45b38d55f4f0"
},
"workspace":
{
"id": "382a1fe6-67cf-481e-9b65-79cfd9e9727f"
}
}
Field nameDescription
account_id
The unique account of this Action. It is always be the same for a given Action.
action_id
The unique id of this Action. It is always be the same for a given Action.
interaction_id
This is a unique identifier generated by Frame.io that you can use to keep track of your transaction. This identifier is the same throughout any sequence of an Action, including callback forms.
project_id
The unique project of this Action. It is always be the same for a given Action.
resource.id
The id of the resource from which you triggered your Action (usually an Asset).
resource.type
The type of resource from which you triggered your Action (usually asset) It can be file,folder or version_stack.
type
The name of the event you put in the Event field when configuring your Action.
user.id
The unique ID to identify the user who triggered the action.
workspace.id
The unique Workspace of this Action. It is always be the same for a given Action.
data
An object of key-value pairs denoting the name of a form element and the value selected and is what the user defines to inform the client url app of a choice being made.

Interactions, Retries and Timeouts

The interaction_id is a unique identifier to track of the interaction as it evolves over time. If you do not need to respond to the user, return a 200 status code, and you're done. While optional, we recommend including information about the result of the action, like a success message or error alert. Custom actions support message callbacks.Frame.io expects a response in less than 10 seconds, and attempts to retry up to 5 times while waiting for a successful response. Ideally the response is immediate and asynchronous actions occur after a trigger via a Custom Action.

Create a Message Callback

In your HTTP response to the webhook event, you can return a JSON object describing a message that will be returned to the initiating user in the Frame.io UI.

Copied to your clipboard
{
"title": "Success!",
"description": "The thing worked! Nice."
}

Messages close the action loop providing variable context to the user, without asking them to switch contexts. When the initial payload and subsequent calls to the Frame.io API don't provide enough context for the receiving application, use Form Callbacks.

Create a Form Callback

Let's say that you need more info before you start your process. For example, you may be uploading content to a system that requires additional details and settings. You can describe a Form in your response, which the user sees snd fills out, and is then sent right back to you! Here's an example form that renders a Form in the Frame.io UI that the acting user can fill out and submit:

Copied to your clipboard
{
"title": "Need some more info!",
"description": "Getting ready to submit this file!",
"fields": [
{
"type": "text",
"label": "Title",
"name": "title",
"value": "MyVideo.mp4"
},
{
"type": "select",
"label": "Captions",
"name": "captions",
"options": [
{
"name": "Off",
"value": "off"
},
{
"name": "On",
"value": "on"
}
]
}
]
}

When the user submits the form, you'll receive an event on the same URL as the initial POST:

Copied to your clipboard
POST /your/url
{
"type": "your-specified-event-name",
"interaction_id": "the-same-id-as-before",
"action_id": "unique-id-for-this-custom-action",
"data":{
"title": "MyVideo.mp4",
"captions": "off"
}
}

All custom fields added on a form appear in the data section of the JSON payload sent by Frame.io. Use the interaction_id to map the initial request and this new form data. And again, you can respond with a message (or even another form!). By chaining Actions, Forms, and Messages, you can effectively program entire Asset workflows in Frame.io with business logic from an external system.

Form Details

Like messages, Forms support title and description attributes that render at the top of the Form. Beyond that, each form field accepts the following base attributes:

  • type -- Tells the Frame.io UI which type of data to expect, and which component and render.
  • label -- Appears on the UI as the header above the field.
  • name -- Key by which the field will be identified on the subsequent payload.
  • value -- Value with which to pre-populate the field.

Supported Field Types

Text Field

A simple text field with no additional parameters.

Copied to your clipboard
{
"type": "text",
"label": "Title",
"name": "title",
"value": "MyVideo.mp4"
}

Text Area

A simple text area with no additional parameters.

Copied to your clipboard
{
"type": "textarea",
"label": "Description",
"name": "description",
"value": "This video is really, really popular."
}

Select List

Defines a picklist that the user can choose from. Must include an options list, each member of which should include a human-readable name, and a machine-parseable value.

Copied to your clipboard
{
"type": "select",
"label": "Captions",
"name": "captions",
"value": "off",
"options": [
{
"name": "Off",
"value": "off"
},
{
"name": "On",
"value": "on"
}
]
}

Checkbox

A simple checkbox with no additional parameters.

Copied to your clipboard
{
"type": "boolean",
"name": "enabled",
"label": "Enabled",
"value": "false"
}

A simple link with no additional parameters.

Copied to your clipboard
{
"type": "link",
"name": "videoLink",
"label": "Video Link",
"value": "https://www.youtube.com/watch?v=XtX1zv9CEVc"
}

The Frame.io Permissions Model

Custom Actions have a special permissions model: they belong to a Workspace, not to any specific user who exists on an Account. That means:

  • Any Content Admin can create a Custom Action on a Workspace.
  • Any Content Admin can modify or delete a Custom Action that exists on a Team. Once modified, all users will immediately see the result of the change.

Security and Verification

By default, all Custom Actions have a signing key generated during their creation. This is not configurable. This key can be used to verify that the request originates from Frame.io. Included in the POST request are the following:

NameDescription
X-Frameio-Request-Timestamp
The time your Custom Action was triggered.
X-Frameio-Signature
The computed signature.
  • The timestamp is the time the request was signed on its way out of Frame.io's network. This can be used to prevent replay attacks. We recommended verifying this time is within 5 minutes of local time.
  • The signature is a HMAC SHA-256 hash using the signing key provided when the Custom Action is first created.

Verifying the Signature

  1. Extract the signature from the HTTP headers.
  2. Create a message to sign by combining the version, delivery time, and request body v0:timestamp:body.
  3. Compute the HMAC SHA256 signature using your signing secret.

Note: The provided signature is prefixed with v0=. Currently Frame.io only has this one version for signing requests. You will need to add this prefix to your computed signature.

Compare!

Copied to your clipboard
import hmac
import hashlib
**def** verify_signature(curr_time, req_time, signature, body, secret):
"""
Verify webhook/custom action signature
:Args:
curr_time (float): Current epoch time
req_time (float): Request epoch time
signature (str): Signature provided by the frame.io API for the given request
body (str): Custom Action body from the received POST
secret (str): The secret for this Custom Action that you saved when you first created it
"""
if int(curr_time) - int(req_time) < 500:
message = 'v0:{}:{}'.format(req_time, body)
calculated_signature = 'v0={}'.format(hmac.new(
bytes(secret, 'latin-1'),
msg=bytes(message, 'latin-1'),
digestmod=hashlib.sha256).hexdigest())
if calculated_signature == signature:
return True
return False
  • Privacy
  • Terms of Use
  • Do not sell or share my personal information
  • AdChoices
Copyright © 2025 Adobe. All rights reserved.