Custom Actions
Custom Actions are user-triggered menu items in the Frame.io UI. They're perfect for building interactive workflows that can present information, ask for user input, and perform tasks on demand.
Why Use Custom Actions?
Custom Actions are ideal when you need to:
- Build interactive workflows that require user input
- Create on-demand tools for specific tasks
- Integrate external services with Frame.io assets
- Automate complex processes with user guidance
- Provide contextual actions based on the selected asset
How Custom Actions Work
- User clicks action in the Frame.io UI (right-click menu, toolbar, etc.)
- Your handler is called with the action event
- Return a response - either a
Message
for simple feedback or aForm
for user input - If Form returned - user fills it out and submits, your handler is called again with the form data
Action Decorator
Use the @app.on_action
decorator to register handlers:
@app.on_action(
event_type="my_app.analyze",
name="Analyze File",
description="Perform analysis on this file",
secret="your-secret"
)
async def analyze_file(event: ActionEvent):
# Handle the action
pass
Parameters
event_type
(str): Unique identifier for this actionname
(str): Display name in Frame.io UIdescription
(str): Description shown in UIsecret
(str): Signing secret from Frame.io
Action Event Object
The ActionEvent
object provides access to action data:
from frameio_kit import ActionEvent
async def handler(event: ActionEvent):
print(event.type) # "my_app.analyze"
print(event.resource_id) # "abc123"
print(event.user.id) # "user_789"
print(event.user.name) # "John Doe"
print(event.data) # None (first call) or dict (form submission)
Response Types
Custom Actions support two response types:
Message
- Simple Feedback
For actions that complete immediately without user input:
from frameio_kit import Message
return Message(
title="Task Complete",
description="Your file has been processed successfully!"
)
Form
- User Input
For actions that need user input:
from frameio_kit import Form, TextField
return Form(
title="Configure Settings",
description="Enter your preferences:",
fields=[
TextField(label="Name", name="name", value="default")
]
)
Form Fields
Field Type | Use Case | Example |
---|---|---|
TextField |
Single line text | Names, titles, IDs |
TextareaField |
Multi-line text | Comments, descriptions |
SelectField |
Choose from options | Categories, platforms |
CheckboxField |
Checkbox toggle | Yes/no, enable/disable |
LinkField |
URL link | External resources |
Example 1: Simple Message
import os
from frameio_kit import App, ActionEvent, Message
app = App()
@app.on_action(
event_type="asset.notify",
name="Notify Team",
description="Send notification about this asset",
secret=os.environ["ACTION_SECRET"]
)
async def notify_team(event: ActionEvent):
print(f"Notification sent for {event.resource_id} by {event.user.name}")
# Send actual notification here
await send_notification(event.resource_id, event.user.id)
return Message(
title="Notification Sent",
description="Your team has been notified about this asset."
)
Example 2: Form with Input
import os
from frameio_kit import App, ActionEvent, Message, Form, TextField, SelectField, SelectOption
app = App()
PLATFORMS = [
SelectOption(name="Twitter", value="twitter"),
SelectOption(name="Instagram", value="instagram"),
]
@app.on_action(
event_type="asset.publish",
name="Publish Asset",
description="Publish this asset to social media",
secret=os.environ["ACTION_SECRET"]
)
async def publish_asset(event: ActionEvent):
# Step 2: Form submitted, process the data
if event.data:
platform = event.data.get("platform")
caption = event.data.get("caption")
print(f"Publishing to {platform}: {caption}")
# Process the publication here
return Message(
title="Published!",
description=f"Asset published to {platform} successfully."
)
# Step 1: Show the form
return Form(
title="Publish to Social Media",
description="Configure your post:",
fields=[
SelectField(label="Platform", name="platform", options=PLATFORMS),
TextField(label="Caption", name="caption", placeholder="Enter your caption...")
]
)
Example 3: Complex Form
import datetime
from frameio_kit import App, ActionEvent, Message, Form, TextField, TextareaField, CheckboxField, DateField
app = App()
@app.on_action(
event_type="asset.schedule",
name="Schedule Review",
description="Schedule a review for this asset",
secret=os.environ["ACTION_SECRET"]
)
async def schedule_review(event: ActionEvent):
if event.data:
reviewer = event.data.get("reviewer")
due_date = event.data.get("due_date")
urgent = event.data.get("urgent", False)
notes = event.data.get("notes", "")
priority = "urgent" if urgent else "normal"
print(f"Scheduling {priority} review with {reviewer} by {due_date}")
return Message(
title="Review Scheduled",
description=f"Review assigned to {reviewer} for {due_date}"
)
return Form(
title="Schedule Review",
description="Set up a review for this asset:",
fields=[
TextField(label="Reviewer Email", name="reviewer", placeholder="reviewer@company.com"),
DateField(label="Due Date", name="due_date", value=datetime.date.today().isoformat()),
CheckboxField(label="Urgent", name="urgent", value=False),
TextareaField(label="Notes", name="notes", placeholder="Additional instructions...")
]
)
Setting Up Custom Actions in Frame.io
- Go to Workspace Settings in Frame.io
- Navigate to Actions section
- Create a new Custom Action:
- Name: Display name in UI
- Description: What the action does
- Event: Must match your
event_type
parameter - URL: Your application's public endpoint
- Secret: Copy the generated secret to your environment variables
- Test the action by right-clicking on an asset
Best Practices
- Keep actions focused - Each action should do one thing well
- Provide clear feedback - Use descriptive titles and messages
- Handle form validation - Check required fields and provide helpful errors
- Use meaningful names - Make event types and display names descriptive
- Test thoroughly - Custom actions are user-facing, so they need to work reliably
- Consider user experience - Keep forms simple and intuitive
Two-Step Process
Custom Actions use a two-step process when returning forms:
- Initial call -
event.data
isNone
, return aForm
- Form submission -
event.data
contains the submitted values, return aMessage