Triggers in Gadget are events or conditions that initiate an action within an application. They parse external events, such as incoming webhooks or API calls, and then run your action with parameters. Default triggers are already established in many actions, such as the API endpoint trigger for integrating the action into your app's API or the Shopify data trigger that executes actions in response to Shopify webhooks.
How triggers work
Each trigger in Gadget does two things:
1. Activates on a certain event: Each trigger is designed to execute at a specific point, determined by various conditions or events. For instance, an API endpoint trigger executes when its corresponding mutation in the GraphQL API is invoked, while a Scheduler trigger activates at pre-set time intervals like a cron job might.
2. Sends the params and trigger to the action: Upon activating, the trigger tests authorization. If successful, the action is run with the params and trigger variables parsed out by the trigger. The contents of the params object depend on the trigger, and the contents of the trigger object describe which trigger ran and why.
Adding Triggers to Actions via the Gadget UI
To add a trigger to an action, click on the action in the Gadget Dashboard's Actions Panel. This will open the action's configuration, where you can define and manage its triggers.
When you select the action, the input parameters will be presented to you, allowing you to fill them out. Clicking the Run button will immediately execute the action, triggering the associated code and applying any changes in real-time.
This feature simplifies the process of running actions by giving you an intuitive interface where you can quickly interact with your actions without having to manually write API calls.
Benefits of Using Gadget's UI for Actions
No-Code Execution - Trigger actions without needing to manually write API calls.
Real-Time Debugging - View the action's execution result or any errors immediately after running the action.
User-Friendly Interface - The UI is simple to use, making the process of triggering actions and debugging easier.
Types of triggers
API endpoint trigger
The API endpoint trigger invokes your action when an incoming API call is made to your application's API. For more on your application's API and how to make API calls, see the API Reference.
By default, most actions have an api trigger already registered. If you want to explicitly register an api trigger, you can do so by adding an api property to the triggers object in the action's options.
api/actions/example.js
JavaScript
import type { ActionOptions } from "gadget-server";
export const options: ActionOptions = {
triggers: {
api: true,
},
};
import type { ActionOptions } from "gadget-server";
export const options: ActionOptions = {
triggers: {
api: true,
},
};
How the API actions are run
The API trigger runs your actions when the corresponding mutation is run in your application's generated API. When this mutation is called, the trigger assesses if the caller has permission to run the action using your application's access control.
If permitted, the action's run function is executed, passing any incoming parameters. For model-scoped actions, the resulting record is sent back to the API caller, and for globally-scoped actions the return value of the run function is sent back. If any errors are thrown during processing, those errors are instead sent back to the caller.
The generated API endpoints for your API triggers can be called using the api object within your application, or using the React hooks from @gadgetinc/react hooks library, or any other GraphQL client.
API endpoint trigger params
The API endpoint trigger validates that incoming parameters match the expected types for the action, and then passes the params to the action.
For model-scoped actions, API triggers add automatic params for each field on the model. For globally-scoped actions, there are no params by default.
You can customize the parameters passed to your actions to suit your specific needs. For more details and examples on adding and customizing parameters, see the action guide.
API endpoint trigger object
When an action is invoked via an API call, the passed trigger object will look like this:
mutationName: the string name of the mutation called in the API.
rootAction: the API identifier of the action triggered by the mutation.
rawParams: the params passed to this API call.
Scheduler trigger
The Scheduler trigger invokes your globally-scoped action at a regular interval. For example, scheduler triggers can be used to send out periodic emails, build database aggregates, or sync data from external systems.
The Scheduler trigger has a scheduler property which describes how often the action should be run, and at what specific times. For example, you can create a scheduler that runs every day at 10:00 AM UTC:
Scheduler triggers also support multiple individual schedules and will invoke your action at each time specified by any included scheduler. For example, we can set up a scheduler to run an action every day at midnight UTC, as well as every Wednesday at noon:
Scheduler triggers can also be expressed using cron syntax, which is a more powerful way to define schedules. For example, the following scheduler options will run an action every day at midnight UTC:
The minimum interval supported by the scheduler trigger is once a minute.
How scheduled actions are run
To add a scheduler trigger, you must specify a time or cron statement that will instruct Gadget on when to run the globally-scoped action. Unlike api triggers, no params will be passed to the action.
Overlapping executions
If a scheduled action is still running when the next scheduled invocation arrives, that next invocation will be skipped. For example, if an action is scheduled to run every minute and it takes 3.5 minutes to complete, the executions that were scheduled during that 3.5-minute window will be skipped.
Schedule trigger params
The Scheduler trigger passes an empty params object when it invokes an action.
If you need to know the current time for executing your action, you can use new Date().
Schedule trigger object
The Scheduler trigger passes a simple trigger object describing the trigger type:
json
{
"type": "scheduler"
}
Trigger Types
Before we dive into filtering, let's first understand Trigger Types. Trigger types define when an action should be executed. Different trigger types exist, such as:
Create - Runs when a new record is created.
Update - Runs when an existing record is modified.
Delete - Runs when a record is deleted.
These trigger types determine when your logic will be executed.
Filtering the trigger type
In addition to using the Gadget UI, you also have the option to define the logic for these actions through code. Here’s an example of how you can define the behavior that runs when an action is triggered programmatically.
JavaScript
/** @type { ActionRun } */
export const run = async ({ params, record, logger, api, connections }) => {
applyParams(params, record); // Apply input parameters to the record
await preventCrossShopDataAccess(params, record); // Prevent cross-shop data access
await save(record); // Save the updated record to the database
}; // in api/actions/example.ts
/** @type { ActionOnSuccess } */
export const onSuccess = async ({ params, record, logger, api, connections }) => {
// Logic to handle success after the action is executed
// Your custom success logic can be added here
};
/** @type { ActionOptions } */
export const options = { actionType: "create" }; // Defines the action as a 'create' type
/** @type { ActionRun } */
export const run = async ({ params, record, logger, api, connections }) => {
applyParams(params, record); // Apply input parameters to the record
await preventCrossShopDataAccess(params, record); // Prevent cross-shop data access
await save(record); // Save the updated record to the database
}; // in api/actions/example.ts
/** @type { ActionOnSuccess } */
export const onSuccess = async ({ params, record, logger, api, connections }) => {
// Logic to handle success after the action is executed
// Your custom success logic can be added here
};
/** @type { ActionOptions } */
export const options = { actionType: "create" }; // Defines the action as a 'create' type
Shopify data trigger
The Shopify data trigger executes model-scoped actions when:
Shopify sends a webhook to your Gadget application
when a missed webhook is detected by Gadget during reconciliation
or when a sync is run and data differences are detected
When this trigger runs, it:
Parses the payload from Shopify, performing HMAC validation on webhooks to ensure authenticity
Transforms the payload into appropriate params for each record described in the payload
Executes the action for each record in the payload, including nested records
Shopify data triggers can also be added to globally-scoped actions to process webhooks there. For more information on how to use Shopify data triggers in globally-scoped check out the guide here. You can include a shopify trigger in Shopify models, but not other models.
Shopify data triggers look like this within your action's options:
To reduce boilerplate, Shopify models do not need to include explicit shopify triggers in their options -- Gadget will apply the correct
triggers by default. It's fine to include a shopify trigger in Shopify models if you want to customize the options, but it's not
required.
Shopify webhook trigger params
For model-scoped actions, the Shopify webhook trigger pulls out the right parameters for the current record from the incoming webhook payload and adjusts the keys to have consistent JavaScript style-casing. For example, when a webhook for product/create arrives, Gadget chops up the payload into the chunk to create params for the root-level product, and then another set of params for each shopifyProductVariant record described in the payload. For this example webhook on the shopifyProduct model, the params object will look like this:
example model-scoped action Shopify Webhook trigger params
For global-scoped actions, the incoming Shopify webhook payload is delivered as the params unchanged. For a product/create webhook, the params object will look like this:
example globally-scoped action Shopify Webhook trigger params
The params delivered for each different webhook topic are different, and they can change when Shopify makes changes. Shopify's field
changes are handled by their API versioning system, ensuring that changes are predictable and managed. For more information on managing
Shopify API versions, see Managing Shopify API Versions
Shopify data trigger object
When a Shopify data trigger invokes an action, it will pass a trigger describing the event that caused the action to run. For the Shopify data trigger, this can be one of two events:
a webhook was received
a sync detected differences
You can detect which type of event occurred by checking the type property of the trigger object:
api/models/shopifyProduct/actions/create.js
JavaScript
export const onSuccess: ActionOnSuccess = async ({ trigger }) => {
if (trigger.type == "shopify_sync") {
// do something because a sync happened
} else {
// do something because a webhook was received
}
};
export const onSuccess: ActionOnSuccess = async ({ trigger }) => {
if (trigger.type == "shopify_sync") {
// do something because a sync happened
} else {
// do something because a webhook was received
}
};
Example webhook trigger object
When a Shopify webhook is received by your Gadget application, the trigger object passed to your action will look like this:
topic: the string representing the topic of the incoming webhook from Shopify, like products/update or orders/create
payload: the raw incoming payload from Shopify, which includes all the data sent by the webhook unchanged
shopId: the identifier for the Shopify store that received the webhook
retries: the number of times this webhook has been retried
The complete payload of the webhook received is accessible within the trigger object that is passed to your action code.
Shopify sync trigger
The Shopify sync trigger is a part of the Shopify data trigger functionality. It executes model-scoped actions when a sync is run and data differences are detected between Shopify and Gadget. This ensures that your Gadget application stays up-to-date with changes in your Shopify store.
How Shopify sync actions are run
When a sync process runs, Gadget compares data between Shopify and your application. If differences are found, the Shopify sync trigger is activated to run the appropriate action, updating the data in Gadget to match Shopify.
Example sync trigger object
When a sync of a particular Shopify shop is run and detects differences, the trigger object passed to your action will look like this:
shopId: The identifier of the Shopify shop being synced
apiVersion: The version of the Shopify API being used for the sync
shopifyScopes: The available OAuth scopes of the Shopify shop being synced
syncId: The identifier of the sync record tracking the state of this sync (optional, only available if set)
syncSince: The specified date range of this sync (optional, only set if specified when the sync was started)
models: The list of model API identifiers that this sync will work on
force: Indicates if this sync is being run in 'force' mode, which will always run actions even if the 'updated_at' timestamps match between Gadget and Shopify
startReason: The string describing the reason why this sync was started (optional, only set if specified when the sync began)
Shopify customer account login trigger
This trigger fetches customer data from Shopify when customer account authentication is enabled in Gadget and a Shopify customer makes a request to a Gadget app from a customer account UI extension.
When the request is made from a customer account UI extension, the customer is assigned a unique session record that is linked to their shopifyCustomer model record. If this shopifyCustomer record does not exist in Gadget, this trigger will be activated to fetch the customer data from Shopify so the customer can be linked to their current session.
This trigger is automatically added to the shopifyCustomer model's create action when customer account authentication is enabled in Gadget. If customer account authentication is disabled, this trigger will be automatically removed.
BigCommerce webhook trigger
The BigCommerce webhook trigger allows you to run globally-scoped actions in response to BigCommerce webhooks.
When you add a BigCommerce webhook trigger to a globally-scoped action, Gadget will automatically register the webhook. You can specify which BigCommerce webhooks should trigger your action by adding a bigcommerce property to the triggers object in the action's options, or by using the Gadget editor to add the trigger and select the webhook topics.
This is what a BigCommerce webhook trigger looks like in your action's options:
BigCommerce webhook payloads typically contain minimal information, often just an ID, about the store and event. Gadget will pull out the important information from the payload and pass it to the action as params. You can then use the included BigCommerce API clientto fetch the full resource data in the action.
For example, this is what the params object might look like for a store/product/created webhook:
example of a params payload for a store/product/created webhook
It is common for BigCommerce webhooks to only include an ID. You will need to use the BigCommerce API client to retrieve the full object data. Here is an example:
api/actions/handleProductCreatedWebhook.js
JavaScript
export const run = async ({ params, api, logger }) => {
const productId = params.id;
const storeHash = params.storeHash;
try {
const product = await api.bigcommerce.products.findOne(productId, {
storeHash: storeHash,
});
logger.info("Retrieved product data:", product);
// Continue with your logic using the full product object
} catch (error) {
logger.error("Failed to retrieve product data:", error);
}
};
export const run = async ({ params, api, logger }) => {
const productId = params.id;
const storeHash = params.storeHash;
try {
const product = await api.bigcommerce.products.findOne(productId, {
storeHash: storeHash,
});
logger.info("Retrieved product data:", product);
// Continue with your logic using the full product object
} catch (error) {
logger.error("Failed to retrieve product data:", error);
}
};
BigCommerce webhook trigger object
The trigger object passed to your action contains the entire webhook payload, as well as additional information about the trigger itself.
This is what the trigger object might look like for a store/product/created webhook:
example of a trigger object for a store/product/created webhook
For BigCommerce webhook triggers, the trigger object will always contain the following properties:
type: will always be set to bigcommerce_webhook
scope: the string representing the topic of the incoming webhook from BigCommerce, like store/product/created or store/order/updated
storeHash: the hash of the BigCommerce store that received the webhook
hash: the hash value of the webhook payload
retries: the number of times this webhook has been retried
createdAt: the timestamp of when the webhook was created
data: the raw incoming payload from BigCommerce, which includes all the data sent by the webhook unchanged
Google OAuth sign up trigger
This trigger is part of the authentication process that integrates Google as an OAuth provider in your application. The entire profile payload from Google plus the additional data from the user model to the action to receive the necessary information from the user's Google profile.
Google OAuth sign up trigger params
When a new user signs up using Google OAuth, the trigger will run your action with params describing the new user, like this:
These params are derived from the Google OAuth callback data passed by Google and adjusted by the trigger to match the fields of the user model. The raw data returned by Google is available in the trigger object.
Google OAuth sign up trigger
The trigger object contains the raw data returned by Google at user object.
Every Gadget web app template by default comes with several out-of-the-box authentication triggers associated with the corresponding authentication actions.
The following authentication triggers although named differently all have the same behavior of the API endpoint trigger.