Triggers
What is a trigger?
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.
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.
1import type { ActionOptions } from "gadget-server";23export const options: ActionOptions = {4 triggers: {5 api: true,6 },7};
1import type { ActionOptions } from "gadget-server";23export const options: ActionOptions = {4 triggers: {5 api: true,6 },7};
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 actions, the resulting record is sent back to the API caller, and for global 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 actions, API triggers add automatic params for each field on the model. For global actions, there are no params by default.
For more on adding parameters to actions, see the action guide.
API endpoint trigger trigger
object
When an action is invoked via an API call, the passed trigger
object will look like this:
an example API trigger objectjson1{2 "type": "api",3 "mutationName": "updateWidget",4 "rootAction": "update",5 "rawParams": {6 "id": "123",7 "widget": {8 "title": "New Widget Title",9 "inventoryCount": 1010 }11 }12}
type
: will always be set toapi
.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 action at a regular interval. For example, scheduled actions 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 Schedule that runs every day at 10:00 AM UTC:
1import type { ActionOptions } from "gadget-server";23export const options: ActionOptions = {4 triggers: {5 scheduler: [{ every: "day", at: "10:00 UTC" }],6 },7};
1import type { ActionOptions } from "gadget-server";23export const options: ActionOptions = {4 triggers: {5 scheduler: [{ every: "day", at: "10:00 UTC" }],6 },7};
Schedule triggers also support multiple individual schedules, and will invoke your action at each time specified by any included schedule. For example, we can set up a scheduler to run an action every day at midnight UTC, as well as every Wednesday at noon:
1import type { ActionOptions } from "gadget-server";23export const options: ActionOptions = {4 triggers: {5 scheduler: [6 { every: "day", at: "00:00 UTC" },7 {8 every: "week",9 on: "Wednesday",10 at: "12:00 UTC",11 },12 ],13 },14};
1import type { ActionOptions } from "gadget-server";23export const options: ActionOptions = {4 triggers: {5 scheduler: [6 { every: "day", at: "00:00 UTC" },7 {8 every: "week",9 on: "Wednesday",10 at: "12:00 UTC",11 },12 ],13 },14};
Schedule 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:
1import type { ActionOptions } from "gadget-server";23export const options: ActionOptions = {4 triggers: {5 scheduler: [{ cron: "0 0 * * *" }],6 },7};
1import type { ActionOptions } from "gadget-server";23export const options: ActionOptions = {4 triggers: {5 scheduler: [{ cron: "0 0 * * *" }],6 },7};
The minimum interval supported by the scheduler trigger is once a minute.
How scheduled actions are run
When you add a Scheduler trigger, Gadget's internal scheduler starts a ticking clock. When the time arrives for a scheduled action to run, Gadget invokes the global 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 trigger
object
The Scheduler trigger passes a simple trigger
object describing the trigger type:
json{"type": "scheduler"}
Shopify data trigger
The Shopify data trigger executes model 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 global actions to process webhooks there. For more information on how to use Shopify data triggers in global actions 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:
1import type { ActionOptions } from "gadget-server";23export const options: ActionOptions = {4 triggers: {5 shopify: {6 webhooks: ["products/create"],7 },8 },9};
1import type { ActionOptions } from "gadget-server";23export const options: ActionOptions = {4 triggers: {5 shopify: {6 webhooks: ["products/create"],7 },8 },9};
To reduce boilerplate, Shopify models don't 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 data trigger params
For model actions, the Shopify data trigger pulls out the right parameters for the current record from the payload and adjusts the keys to have consistent JavaScript style-casing. For example, when a webhook for a product/create
webhook 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 action Shopify Webhook trigger paramsjson1{2 "id": "12345",3 "shopifyProduct": {4 "title": "Example T-Shirt",5 "tags": ["example", "t-shirt"],6 "publishedAt": "2024-01-01T00:00:00Z",7 "productCategory": {8 "id": "12345",9 "name": "Shirts"10 }11 // ... etc12 }13}
and for the shopifyProductVariant
model, the params
object will look like this:
example model action Shopify Webhook trigger paramsjson1{2 "id": "5678",3 "shopifyProductVariant": {4 "title": "Example T-Shirt",5 "sku": 10,6 "price": 10.99,7 "inventoryPolicy": "continue",8 "fulfillmentService": "manual"9 // ... etc10 }11}
For global 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 global action Shopify Webhook trigger paramsjson1{2 "topic": "products/create",3 "payload": {4 "admin_graphql_api_id": "gid://shopify/Product/788032119674292922",5 "body_html": "An example T-Shirt",6 "created_at": null,7 "handle": "example-t-shirt",8 "id": 7880321196742929229 // ... etc10 }11}
The params
delivered for each different webhook topic are different, and they can change when Shopify makes changes.
Shopify data trigger 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:
1export const onSuccess: ActionOnSuccess = async ({ trigger }) => {2 if (trigger.type == "shopify_sync") {3 // do something because a sync happened4 } else {5 // do something because a webhook was received6 }7};
1export const onSuccess: ActionOnSuccess = async ({ trigger }) => {2 if (trigger.type == "shopify_sync") {3 // do something because a sync happened4 } else {5 // do something because a webhook was received6 }7};
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:
json1// An example Shopify Webhook trigger2{3 "type": "shopify_webhook",4 "topic": "products/update",5 "payload": {6 "id": 788032119674292900,7 "title": "Example T-Shirt",8 "body_html": "An example T-Shirt",9 "vendor": "Acme",10 "product_type": "Shirts",11 "created_at": null,12 "handle": "example-t-shirt"13 // ... etc matching Shopify's format exactly14 },15 "shopId": "shop123",16 "retries": 017}
type
: will always be set toshopify_webhook
topic
: the string representing the topic of the incoming webhook from Shopify, likeproducts/update
ororders/create
payload
: the raw incoming payload from Shopify, which includes all the data sent by the webhook unchangedshopId
: the identifier for the Shopify store that received the webhookretries
: 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.
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:
An example Shopify Sync triggerjson1{2 "type": "shopify_sync",3 "shopId": "123456",4 "apiVersion": "2023-01",5 "shopifyScopes": ["read_products", "write_products"],6 "syncId": "1",7 "syncSince": null,8 "models": ["shopifyShop", "shopifyProduct"],9 "force": false,10 "startReason": undefined // will be "scheduled" if Action ran via daily sync11}
type
: Will always be set toshopify_sync
shopId
: The identifier of the Shopify shop being syncedapiVersion
: The version of the Shopify API being used for the syncshopifyScopes
: The available OAuth scopes of the Shopify shop being syncedsyncId
: 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 onforce
: 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 ShopifystartReason
: 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 global actions in response to BigCommerce webhooks.
When this trigger runs, it:
- Parses the payload from BigCommerce, following the BigCommerce best practices for webhook security
- Adds the raw webhook payload to
params
- Executes the action
When you add a BigCommerce webhook trigger to a global 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:
1import type { ActionOptions } from "gadget-server";23export const options: ActionOptions = {4 triggers: {5 api: false,6 bigcommerce: {7 webhooks: ["store/product/created"],8 },9 },10};
1import type { ActionOptions } from "gadget-server";23export const options: ActionOptions = {4 triggers: {5 api: false,6 bigcommerce: {7 webhooks: ["store/product/created"],8 },9 },10};
BigCommerce webhook trigger params
BigCommerce webhook payloads contain minimal information 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 client to 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 webhookjson{"id": 1,"storeHash": "<your-store-hash>","type": "product"}
The params delivered for each different webhook topic are different, and they can change when BigCommerce makes changes.
BigCommerce webhook trigger 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 webhookjson1{2 "createdAt": 1723578525,3 "data": {4 "id": 1,5 "type": "product"6 },7 "hash": "<your-hash-value>",8 "retries": 0,9 "scope": "store/product/created",10 "storeHash": "<your-store-hash>",11 "type": "bigcommerce_webhook"12}
For BigCommerce webhook triggers, the trigger
object will always contain the following properties:
type
: will always be set tobigcommerce_webhook
scope
: the string representing the topic of the incoming webhook from BigCommerce, likestore/product/created
orstore/order/updated
storeHash
: the hash of the BigCommerce store that received the webhookhash
: the hash value of the webhook payloadretries
: the number of times this webhook has been retriedcreatedAt
: the timestamp of when the webhook was createddata
: 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:
example Google OAuth Sign Up paramsjson1{2 "user": {3 "email": "[email protected]",4 "emailVerified": true,5 "firstName": "Giz",6 "googleImageUrl": "https://gmail.com/some/image.png",7 "googleProfileId": "113836975668244786030",8 "lastName": "Mo",9 "roles": ["signed-in"]10 }11}
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 trigger
The trigger
object contains the raw data returned by Google at user
object.
example Google OAuth Sign Up triggerjson1{2 "type": "google_oauth_signup",3 "user": {4 "email": "[email protected]",5 "email_verified": true,6 "family_name": "Mo",7 "given_name": "Giz",8 "hd": "gadget.dev",9 "name": "Giz Mo",10 "picture": "https://gmail.com/some/image.png",11 "sub": "113836975668244786030"12 }13}
Default email/password authentication triggers
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.
- Sign up
- Sign in
- Verify email
- Reset password
- Send reset password
- Send verify email
- Change password