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 transmit them to the rest of the Action. Default triggers are already established in many Actions, such as the GraphQL API trigger for integrating the Action into your app's API or the Shopify Webhook trigger that executes Actions in response to Shopify webhooks.
Types of triggers
GraphQL API trigger
The GraphQL API trigger in Gadget enables the invocation of actions through the GraphQL API generated for your application. Each action associated with a GraphQL API trigger is represented by a corresponding mutation. When this mutation is triggered, the action is executed, and the resulting record or errors are returned by the GraphQL API. These mutations can be easily called from the JavaScript client of your application, providing a convenient and straightforward way to interact with and trigger actions through the GraphQL API.
For example, if we add a publish
action to a Post model in the Gadget editor, the GraphQL API will get a new publishPost
mutation:
GraphQL1mutation PublishPost($id: GadgetID!, $post: PublishPostParams!) {2 publishPost(id: $id, post: $post) {3 success4 errors {5 message6 }7 post {8 id9 title10 publishedAt11 }12 }13}
You can also call the publishPost
mutation with the generated JS client in a JS script:
JavaScriptimport { Client } from "@gadget-client/blog-post-example";const client = new Client();await client.post.publish(123, { post: { publishedAt: new Date() } });
Or call the mutation from a React app using the @gadgetinc/react
hooks library:
JavaScript1import { useAction } from "@gadgetinc/react";2import { api } from "../api"; // some file which instantiates the Client34export const CreatePost = (props) => {5 const [{ data, fetching, error }, act] = useAction(api.post.publish);67 if (fetching) {8 return <div>Saving...</div>;9 }1011 if (error) {12 return <div>Error: {error.message}</div>;13 }1415 return (16 <button17 onClick={() => {18 act(123, { post: { publishedAt: new Date() } });19 }}20 >21 Publish Post22 </button>23 );24};
Scheduler trigger
You can use the scheduler trigger if you want to run your action on a regular schedule, similar to scheduling a cron job. For example, perhaps you would like to fetch some data from another service every hour or summarize your Gadget data every Thursday at midnight. Every Global Action is allowed to have one scheduler trigger, which you can add by clicking the plus icon next to the triggers panel:

When you add the scheduler trigger card above your code file, you will be able to change the schedule or add more entries to the schedule. For example, you will need five entries - one for each day - to have a schedule that runs at 4 PM every weekday.
The scheduler trigger does not prevent duplicate calls from overlapping schedule items. For example, if you have a schedule with one entry that runs every hour, on the hour, and another entry for every day at 5:00 PM, your action will run twice every day at 5:00 PM.
Since the scheduler trigger executes a Global Action like the API, all logs emitted from the Action can be found in the log viewer.
Any execution of a scheduled Global Action that overlaps a previously scheduled execution that is still running will be ignored. For example, suppose you have a schedule that runs a Global Action every minute. If an execution at 10:50 takes 3.5 minutes to run, the executions that were scheduled for 10:51, 10:52, and 10:53 will be ignored, and the next scheduled execution of the Global Action will be at 10:54. Any execution that fails will be retried 4 times, so a maximum of 5 attempts. Similar to overlapping executions, retries will also cause overlapping scheduled executions to be ignored.
The Scheduler trigger supports invoking your Global Actions using a cron expression. To use a cron expression, select the cron
option in the interval list, and enter a valid cron expression. Like the other interval types, cron expressions are additive, where multiple cron expressions will be combined to create the schedule.
For more on cron expressions, see https://crontab.guru.
Webhook trigger
Webhook triggers in Gadget provided from Shopify is dependent on establishing a Shopify connection. Once the connection is set up, Gadget can receive webhooks sent by Shopify. When Gadget receives a webhook from Shopify, it performs an authenticity verification process and triggers the corresponding Action associated with the webhook.
The complete payload of the webhook received from Shopify is accessible within the trigger object that is passed to your Action code. This allows you to access and utilize the entire webhook payload data within your Action's logic and processing.
Webhook retries
If the Action fails for any reason, Gadget will retry up to 10 times with an increasing delay between each attempt.
The same traceId
is used for each retry. This traceId
can be used to filter a Gadget app's Logs to see details about each attempt, for example, {environment_id="123"} | json | level=~"warn|error" | trace_id="21a0324a67729a47ded4b33046afcffe"
.
If the Action fails on the last attempt, the webhook is "lost," but your next daily sync should ensure that the affected records in Gadget are brought back in sync with Shopify.
Shopify sync trigger
In order to maintain data synchronization with Shopify, relying solely on webhooks is not sufficient. To adhere to Shopify's best practices, most Shopify models in Gadget also receive a sync trigger.
This sync trigger is responsible for reconciling any missed webhooks and ensuring data is kept up to date. The sync process runs once a day and serves two primary purposes. Firstly, it ensures that any data from missed webhooks within the past day is captured and integrated into the Gadget system, thus keeping the data up to date. Secondly, it guarantees that models that do not receive webhooks directly are still updated and synchronized with the latest information.
By incorporating the sync trigger, Gadget ensures that data consistency is maintained and any gaps or missed updates are addressed on a daily basis, aligning with Shopify's recommended approach for data synchronization.
Actions that fail during sync are not retried. You can visit the Shopify Connection page to find the failed sync and view the logs for that sync.
Trigger descriptors
Each action is passed a trigger
object that contains information related to what event triggered the action to run. The trigger
object is different for each type of trigger that can call an action and has a type
object describing which type of trigger fired.
models/someModel/someAction.jsJavaScriptexport async function run({ api, record, trigger }) {console.log(trigger); // will log an object like { "type": "api", "rootModel": "someModel", "rootAction": "someAction", etc ... }}
api
trigger
api
triggers describe calls to your Gadget app's GraphQL API, like those made by the JS client or in the GraphQL playground.
An example API triggerjson1{2 "type": "api",3 "mutationName": "updateWidget",4 "rootModel": "widget",5 "rootAction": "update",6 "rawParams": {7 "id": "123",8 "widget": {9 "title": "New Widget Title",10 "inventoryCount": 1011 }12 }13}
Properties
type
: will always be set to"api"
mutationName
: the string name of the mutation called in the APIrootModel
: the API identifier of the Model the mutation was called on. Can be different than the root-level model when invoking Nested Actions. Is not set for Global Actions.rootAction
: the API identifier of the Action triggered by the mutation. Can be different than the root-level action when invoking Nested Actions.rawParams
: the params passed to this API call, including any data for nested actions if passed
scheduler
trigger
scheduler
triggers describe actions invoked by the built-in Scheduler within Gadget. No other data is currently passed with this type of trigger.
json{"type": "scheduler"}
shopify_sync
trigger
shopify_sync
triggers describe actions run by Gadget's Shopify Sync, including daily syncs and manual syncs.
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}
Properties
type
: will always be set to "shopify_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_webhook
trigger
shopify_webhook
triggers describe actions that occur in response to Shopify webhooks, such as 'products/update' or 'orders/create'.
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}
Properties
type
: will always be set to"shopify_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
shopify_oauth
trigger
shopify_oauth
triggers describe actions invoked during the installation of an app through the Shopify Partners connection process. No other data is currently passed with this type of trigger.
json{"type": "shopify_oauth"}
shopify_admin
trigger
shopify_admin
triggers describe actions invoked during the installation of a Shopify app provisioned in the Shopify Admin. No other data is currently passed with this type of trigger.
json{"type": "shopify_admin"}