# Forward Shopify data to an external service  Time to build: ~10 minutes Gadget simplifies the process of forwarding Shopify data to external services, like ERPs or PIMs. It can also be used to build a two-way data sync between Shopify and another service. In this tutorial, you will learn how to build a middleware application that forwards new `orders` from Shopify to an existing service: The [Shopify connection](https://docs.gadget-canary.xyz/guides/plugins/shopify) handles Shopify's auth, webhooks subscriptions, and historical data sync. [Background actions](https://docs.gadget-canary.xyz/guides/actions/background) make it simple to summon the infrastructure you need to reliably move data between systems and deal with rate limits, retries, and errors. ## Prerequisites  Before starting, you will need: * A [Shopify Partner account](https://partners.shopify.com/) * A [Shopify development store](https://help.shopify.com/en/partners/dashboard/managing-stores/development-stores) ## Step 1: Create a Gadget app and connect to Shopify  The first step is to create a new Gadget app and connect it to Shopify. 1. Create a new Gadget app at [gadget.new](https://gadget.new). 2. Follow the [Shopify quickstart](https://docs.gadget-canary.xyz/guides/plugins/shopify/quickstart) guide to connect to Shopify. For this tutorial, you need the `read_orders` scope and the `order` model: You will be prompted to request access to [protected customer data](https://docs.gadget-canary.xyz/guides/plugins/shopify/building-shopify-apps#protected-customer-data-access-pcda). This is required to be able to subscribe to `orders/*` webhooks and sync order data. Fill out the required part of the form (**Protected customer data**) in the [Partners dashboard](https://partners.shopify.com/) before you install your app on a development store. Gadget will copy the selected `shopifyOrder` model, field types and validations, and relationships into your Gadget backend. These models are ready to process webhooks or sync historical data as soon as you install the app on a Shopify store. ## Step 2: Create a custom action to forward orders  Now that you have connected to Shopify, create a custom action to forward order data to another service. 1. Create a new action by adding a file in `api/models/shopifyOrder/actions` called `forward.js` (click **+** to create a new action) 2. Paste the following code into `forward.js`: ```typescript import { applyParams, ActionOptions } from "gadget-server"; export const run: ActionRun = async ({ params, record, logger }) => { applyParams(params, record); // make request to third-party service or ERP // in this case, a separate Gadget app is acting as this service const response = await fetch("https://orders-request-bin.gadget.app/data", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(record), }); if (response.ok) { const responseMessage = await response.text(); logger.info({ message: responseMessage }); } else { // throw an error and the action will be retried by the background action queue throw new Error(`ERROR: ${response.status} - ${response.statusText}`); } }; export const options: ActionOptions = { // note the custom action type! actionType: "custom", triggers: { api: true, }, }; ``` This action simply uses Node's built-in `fetch` call to send data to an external service. If the request is successful, the response is logged. If the request fails, an `Error` is thrown and the action will be retried by the background action queue. Replace the `fetch` call with the appropriate method for sending data to your existing service. For example, you might use a client library to send data to an ERP system. Now all you need to do is add a `forward` action call to the background action queue whenever a new order is created. ## Step 3: Add actions to the queue  We want to add our `forward` action calls to our background action queue. We can do this from the `shopifyOrder` model's `create` action. The `create` action will be called when a Shopify `orders/create` webhook is fired or a historical data sync is run. 1. Paste the following code into `api/models/shopifyOrder/actions/create.js`: ```typescript import { applyParams, save, ActionOptions } from "gadget-server"; import { preventCrossShopDataAccess } from "gadget-server/shopify"; export const run: ActionRun = async ({ params, record }) => { applyParams(params, record); await preventCrossShopDataAccess(params, record); await save(record); }; export const onSuccess: ActionOnSuccess = async ({ record, api }) => { // enqueue the shopifyOrder.forward action await api.enqueue( api.shopifyOrder.forward, // shopifyOrder.forward takes a single param: the id of the order record // the `record` param in the `forward` action will contain the full order data { id: record.id }, { // providing a named queue limits max concurrency to 1 // only a single queued action runs at a time // this helps manage a rate limit of 10 req/second on the external service queue: "forward-orders-queue", } ); }; export const options: ActionOptions = { actionType: "create" }; ``` The `api.enqueue()` function adds the `forward` action to the background action queue. `enqueue()` takes the action to be enqueued as the first argument, and the parameters to be passed to the action as the second argument. The third parameter defines retry and concurrency settings for background actions. We provide a named queue to limit the maximum concurrency to 1, which helps deal with rate limits on the external service. ## Step 4: Test the app  That's all that is required to implement a middleware application that forwards Shopify orders to an existing service. You can test the app by: 1. Creating a new order in your Shopify store (via the admin or storefront) OR running a historical data sync in Gadget (**Installs** > **Sync**). 2. Click on **Queues** in the editor to view your background action queue. You should see all actions that have been added to the queue, whether they are waiting to be run, encountered an error and are retrying, or have run successfully. 3. You should see the order data logged in your **Logs** for successful action runs. Congrats! You have built a middleware application that forwards Shopify orders to an external service. ## Next steps  Have questions about the tutorial? Ask the Gadget team in our developer [Discord](https://ggt.link/discord). ### Building a two-way sync  You can also build a two-way sync between Shopify and your external service. Two-way syncs keep data consistent between two systems. Typically, a two-way sync is built by: * Forwarding data from Shopify to the external service using the method described in this tutorial. * Adding an [HTTP route](https://docs.gadget-canary.xyz/guides/http-routes) to your Gadget app that can be used to subscribe to webhooks from the external service OR adding a [scheduled action](https://docs.gadget-canary.xyz/guides/actions/triggers#scheduler-trigger) to periodically poll the external service for updates. * Using another custom action and background actions to forward updates to Shopify. * Using timestamps or the [`Record` API's change detection](https://docs.gadget-canary.xyz/api/example-app/development/gadget-record#gadgetrecord-api) to avoid webhook loops (where a record is updated in Shopify > forwarded to the external service > which triggers a webhook back to Gadget > which updates the record in Shopify > and so on). ### Webhook filtering  Gadget supports Shopify webhook filtering, allowing you to subscribe to a subset of events for a given webhook topic. For example, you can subscribe to `orders/create` webhooks only for orders over $100. Filtering can drastically reduce the number of webhooks that need to be processed by your app (and lower the amount of request time used for middleware applications). [Read more about Shopify webhook filtering](https://docs.gadget-canary.xyz/guides/plugins/shopify/shopify-webhooks#filtering-shopify-webhooks).