Blog
/
Editorial

Understanding Shopify Functions. Part 2: What can they do, and how to build with them

Published
February 23, 2023
Last updated
January 18, 2024
Learn how Shopify Functions work, which Functions APIs exist, what the major limitations are, and how to use them in your next Shopify app build.

Last week, we did a deep-dive into what the new Shopify Functions means for the future of building with Shopify. Now, let’s talk about how to use them.

We’ll cover how Shopify Functions work, which Functions APIs exist, major limitations, and give an example of a useful development workflow to get started. 

It’s a long read, but trust us it’ll be worth your time. Let’s get into it!

How do Shopify Functions work?

At their core, Shopify Functions are small pieces of code which take input, process it, and write output that Shopify uses to customize a very specific part of the buyer experience. The most powerful thing about Functions is that they execute in Shopify’s backend, not on the app developers’ infrastructure. 

Functions are distributed just like any other custom or public app. When a merchant installs an app that leverages Functions, the function is installed on their store. Depending on the type of function and what customization capabilities the app developer has added, the merchant can configure the function to meet their specific needs. 

Say you built a Shopify app that enables merchants to create discounts that automatically apply X% discount on the shipping rate of an order whenever the total cart value is above $Y. You’d need to build an embedded app UI that allows the merchant to create the discount, and configure variables X and Y. 

Once installed on a store, Shopify hosts the function and makes sure to execute it whenever a buyer touches the relevant part of a Shopify store. In the example above, Shopify would execute the shipping discount function when a buyer loads the shipping selection step of a checkout.

The lifecycle of a Shopify Function, from Shopify’s documentation

Any Shopify merchant can use public Shopify apps that leverage Functions, but only Plus merchants can use custom apps. So if you’re a Shopify app developer, you either need to publish your app to the Shopify app store for anyone to use it, or offer it to individual Plus merchants as a custom app. And because Shopify hosts and runs the function, you don’t have to lose sleep over scaling your app’s infrastructure if a big brand installs your app and uses it during a flash sale.

Because Functions are self-contained pieces of logic that run in parallel, and aren’t aware of each other, they can’t be chained. In other words, you can't use output from one function as input in another. And to handle scenarios where several Functions run in parallel each Functions API has an algorithm for combining the result.

What Functions can you build?

Shopify started rolling out the first Functions in June 2022, and we expect them to keep adding more. As of February 2023, there are four publicly available Functions APIs and another four in developer preview or beta. 

Currently, the publicly available APIs can be installed by merchants, while the developer preview and beta Functions can only be installed by development stores until Shopify promotes them to be generally available. Something that they have in common however, is that they will not work for merchants that use checkout.liquid.

Publicly available Functions APIs

Let’s start with the publicly available Functions APIs, which you could build an app that merchants could use today. These are the four already available:

  • Order Discount API
  • Product Discount API 
  • Delivery Customization API
  • Payment Customization API

The Order Discount and Product Discount APIs are pretty straightforward, and probably the two that most of us can relate to from our own online shopping experiences. They simply give you the ability to create automated discount logic that applies to a cart. The big difference is that the Order Discount applies to an entire order, while the Product Discount applies to individual products. 

In the case of the Order Discount API, you can apply a fixed amount like $10 off the entire cart, a percentage-based discount such as 15%, or create tiered discounts like spend $200 to get 20% off. 

The Product Discount API can apply amount or percentage-based discounts to individual products or variants, create discounts based on quantity of products, or create logic that provides free products if you buy a certain quantity of a specific product. 

Your function runs the logic that determines if the discount should be applied. As an example, you could give a discount to customers tagged with a particular tag without having to distribute a discount code to them.

And if a merchant has apps that leverage both Order Discount and Product Discount functions, they will run in parallel, and be fed into an algorithm that decides how they get applied to an order. Shopify has disclosed that they’re working on the ability for Order and Product discounts to be combined, with tentative availability in mid-2023. And they’re also looking to eventually support line item discounts, possibly being released in the second half of 2023. 

The Delivery Customization API enables you to customize what or how delivery options are displayed to buyers. This can be used to hide delivery options for certain products, customers, or PO box addresses, choose which order delivery options are displayed to buyers, or add messaging to delivery options. 

Example Delivery Customization API experience, from Shopify’s documentation.

Lastly, the Payment Customization API similarly allows you to customize which payment methods are displayed to buyers during the checkout experience, or in which order they appear. You can choose to hide payment methods based on the cart value, e.g. not show credit card payments for orders above $5000 because you’re worried about fraud on high-value orders, or hide payment methods for certain customers.

Functions in Developer Preview and Beta 

As new Functions are released, Shopify is making them available early on for their more eager users. As with all beta products there will be some challenges, but who knows – the head start might make you the first person to solve a specific problem. There are four options today:

  • Cart and Checkout Validation API
  • Cart Transform API (Beta)
  • Shipping Discount API
  • Order Routing Location Rule API

The Cart and Checkout Validation API will enable a store to gate orders to proceed by applying validation to them. This can be powerful for brands that have product limitations, like scarce inventory, limited drops, or products that should only be available to certain customer segments. Think of it as this: what needs to be true for this order to be let through, or what can’t be true for it to be let through? Does the customer require a customer membership, provide a specific digital token (tokengating), or do they need to verify their age? Are they allowed to have at most 4 of a specific product or a cart value of at most $1,000? If a cart doesn’t pass the validation, buyers will see a banner explaining why they can’t complete the purchase. Shopify will eventually provide more flexibility around where a Function can display such validation messages.

The Cart Transform API will make it easier to build cart experiences that better represent the relationship between items in the cart. Instead of showing several line items, you can show them as a single bundle, or show the individual items of a bundle. You can also show Buy One Get One items on a single line, or add and display a free gift. Once the Cart Transform API is promoted to general availability, functions built with this will run every time the cart is updated. This will enable brands to match what the cart displays with how they present relationships between products to buyers, and how they want buyers to think about them.

The Shipping Discount API is similar to previously mentioned discount Function APIs. It allows you to automatically apply discounts to shipping rates at checkout; e.g. offer free shipping, or discounted shipping such as $10 or 15% off. Shipping costs – specifically “surprise” costs – can be a common reason for why buyers abandon their cart. By automating discount logic in this crucial step, merchants may be able to lower the bar for buyers to pass this hurdle and complete their purchase. 

Last and perhaps most niche of the current Function APIs is the Order Routing Location Rule API, likely only useful for some larger merchants that have multiple distribution locations. With this function, you can ‘route’ where line items of an order should be fulfilled from by ranking the order of locations the logic should choose from. You can even deprioritize a location if it already reached a set limit of orders for the day. With this, you can make decisions based on current spare fulfillment capacity or which location is closest to a buyer. Note that if this is what you want to build with, you’re required to email Shopify to gain access. 

Languages and limitations

Once you’ve decided which Function API you’ll build with, we strongly recommend that you read Shopify’s documentation for it, because there may be limitations of when or how it will work. Examples include when the buyer is using Shop Pay, renaming payment methods that have logos, and limitations on modifying delivery options. 

Shopify has also put some other limitations in place. The most important ones are that Functions need to be deterministic, which means you can’t introduce randomness and the same input always produces the same output, they must execute within 5ms, and a function’s output can’t exceed 20kb. 

The limitations are there primarily to guarantee that the buyer experience is not negatively impacted by slow loading, and that Shopify can run the Functions at scale. In a Functions AMA, Shopify PMs have stated that they plan on moving towards a fuel-based system for measuring function performance, as execution time can differ when the same function is run on different hardware.

To build Functions you can use almost any language that compiles down to WebAssembly (Wasm), such as AssemblyScript or Rust. But not all languages are equal. Rust was for a long time the language of choice on Shopify’s end, which means that their tutorials and tooling were primarily Rust. One reason was that the compiled .wasm file needs to be under Shopify’s size limit which as of writing is 256kB, it was hard to achieve with e.g. JavaScript. But in April 2023 Shopify announced the general availability of JavaScript support for Functions APIs, and has added documentation and tutorials for how to build Functions with JS. 

Let’s skip the talk, and start developing! 

Once you’ve figured out a Functions API endpoint and language you want to build with, how do you start building? Follow our example workflow to get started, and feel free to adjust along the way. We also recommend taking a look at Shopify’s suggestions.

To create a Shopify app that uses Functions you’ll need to use Shopify’s CLI. Create your app, then generate the function extension. The CLI will prompt you to select an extension upfront, so you need to know what function you want to build before you start building! After picking a Function API, you will be prompted to select either Wasm or Rust.

Choose which Functions API you want to use.

Selecting Wasm gives you a new extension folder in your CLI app and sets up some basic scaffolding in the form of GraphQL files that define the input and schema of the function. If you pick Rust you get the same GraphQL files, but Shopify also automatically imports some useful Rust packages (in Cargo.toml), sets up build commands in the shopify.function.extension.toml file, and gives yous main.rs and tests.rs files that act as a starting place for function development.

Choose which language you want to build with.

If you are building in Rust, a good first step is to make sure that the default scaffolding works as expected. After installing Rust on your computer, you can simply run cargo test from the function extension root folder to install all dependencies and run the default test.

If you have decided to build in a language other than Rust, you’ll need to do a few things:

  1. Build your own function scaffolding that can read from STDIN and write to STDOUT using the WebAssembly System Interface (WASI). (You can test your function scaffolding with Shopify’s function-runner CLI. Here’s a quick example using AssemblyScript.)
  2. Make sure you can deserialize your function input and serialize your function output.
  3. Write a build command that compiles your function code down to a Wasm file. 
  4. Add that build command to the <inline-code>shopify.function.extension.toml<inline-code> file included in your extension folder. This ensures that your function code will be compiled down to Wasm when you run the deploy command from the Shopify CLI.

Shopify plans on integrating function-runner right into the Shopify CLI so that function testing can be done without loading a separate tool.

Next, think about what your function output should look like, and what input you need to make it happen. Shopify’s Function input and output documentation is invaluable in this step, so make sure to read it. The deterministic nature of Functions make this a great opportunity to follow test-driven development. Write out your unit tests first with the input and expected output, then write your function code to ensure that your tests pass.

Reading Shopify’s guides for a specific Function API will also help you capture any specific context, or learn how to test it in practice. You’ll find it under the Getting Started section in their Functions API docs, where they provide step-by-step instructions, sample code, and descriptions of where in the Shopify Admin to choose, configure, or enable a specific function. 

Another useful tip: Functions also have a page in the Partner dashboard (in the Extensions tab of your Shopify app) where you can review your function’s performance; how many times has it run, how often it exceeds the 5ms time limit, what the function input and output are when it runs, and more. This is useful to debug or monitor your function both during development, as well as when it’s in the hands of merchants. If your function fails to run, you can use the provided function input to add another test to your extension and fix the issue.

We hope you found this deep-dive useful. If you want to get started with Shopify Functions but don’t already have an idea in mind, watch our workshop on Shopify functions and extensions. By the end of it, you should be better prepared to tackle any functions ideas you may have. 

If you have any questions about Shopify Functions, or how to get started building with them, pop into our developer Discord community. We’d be happy to help!

Ralf Elfving
Author
Reviewer
Try Gadget
See the difference a full-stack development platform can make.
Create app

Understanding Shopify Functions. Part 2: What can they do, and how to build with them

Learn how Shopify Functions work, which Functions APIs exist, what the major limitations are, and how to use them in your next Shopify app build.
Problem
Solution
Result

Last week, we did a deep-dive into what the new Shopify Functions means for the future of building with Shopify. Now, let’s talk about how to use them.

We’ll cover how Shopify Functions work, which Functions APIs exist, major limitations, and give an example of a useful development workflow to get started. 

It’s a long read, but trust us it’ll be worth your time. Let’s get into it!

How do Shopify Functions work?

At their core, Shopify Functions are small pieces of code which take input, process it, and write output that Shopify uses to customize a very specific part of the buyer experience. The most powerful thing about Functions is that they execute in Shopify’s backend, not on the app developers’ infrastructure. 

Functions are distributed just like any other custom or public app. When a merchant installs an app that leverages Functions, the function is installed on their store. Depending on the type of function and what customization capabilities the app developer has added, the merchant can configure the function to meet their specific needs. 

Say you built a Shopify app that enables merchants to create discounts that automatically apply X% discount on the shipping rate of an order whenever the total cart value is above $Y. You’d need to build an embedded app UI that allows the merchant to create the discount, and configure variables X and Y. 

Once installed on a store, Shopify hosts the function and makes sure to execute it whenever a buyer touches the relevant part of a Shopify store. In the example above, Shopify would execute the shipping discount function when a buyer loads the shipping selection step of a checkout.

The lifecycle of a Shopify Function, from Shopify’s documentation

Any Shopify merchant can use public Shopify apps that leverage Functions, but only Plus merchants can use custom apps. So if you’re a Shopify app developer, you either need to publish your app to the Shopify app store for anyone to use it, or offer it to individual Plus merchants as a custom app. And because Shopify hosts and runs the function, you don’t have to lose sleep over scaling your app’s infrastructure if a big brand installs your app and uses it during a flash sale.

Because Functions are self-contained pieces of logic that run in parallel, and aren’t aware of each other, they can’t be chained. In other words, you can't use output from one function as input in another. And to handle scenarios where several Functions run in parallel each Functions API has an algorithm for combining the result.

What Functions can you build?

Shopify started rolling out the first Functions in June 2022, and we expect them to keep adding more. As of February 2023, there are four publicly available Functions APIs and another four in developer preview or beta. 

Currently, the publicly available APIs can be installed by merchants, while the developer preview and beta Functions can only be installed by development stores until Shopify promotes them to be generally available. Something that they have in common however, is that they will not work for merchants that use checkout.liquid.

Publicly available Functions APIs

Let’s start with the publicly available Functions APIs, which you could build an app that merchants could use today. These are the four already available:

  • Order Discount API
  • Product Discount API 
  • Delivery Customization API
  • Payment Customization API

The Order Discount and Product Discount APIs are pretty straightforward, and probably the two that most of us can relate to from our own online shopping experiences. They simply give you the ability to create automated discount logic that applies to a cart. The big difference is that the Order Discount applies to an entire order, while the Product Discount applies to individual products. 

In the case of the Order Discount API, you can apply a fixed amount like $10 off the entire cart, a percentage-based discount such as 15%, or create tiered discounts like spend $200 to get 20% off. 

The Product Discount API can apply amount or percentage-based discounts to individual products or variants, create discounts based on quantity of products, or create logic that provides free products if you buy a certain quantity of a specific product. 

Your function runs the logic that determines if the discount should be applied. As an example, you could give a discount to customers tagged with a particular tag without having to distribute a discount code to them.

And if a merchant has apps that leverage both Order Discount and Product Discount functions, they will run in parallel, and be fed into an algorithm that decides how they get applied to an order. Shopify has disclosed that they’re working on the ability for Order and Product discounts to be combined, with tentative availability in mid-2023. And they’re also looking to eventually support line item discounts, possibly being released in the second half of 2023. 

The Delivery Customization API enables you to customize what or how delivery options are displayed to buyers. This can be used to hide delivery options for certain products, customers, or PO box addresses, choose which order delivery options are displayed to buyers, or add messaging to delivery options. 

Example Delivery Customization API experience, from Shopify’s documentation.

Lastly, the Payment Customization API similarly allows you to customize which payment methods are displayed to buyers during the checkout experience, or in which order they appear. You can choose to hide payment methods based on the cart value, e.g. not show credit card payments for orders above $5000 because you’re worried about fraud on high-value orders, or hide payment methods for certain customers.

Functions in Developer Preview and Beta 

As new Functions are released, Shopify is making them available early on for their more eager users. As with all beta products there will be some challenges, but who knows – the head start might make you the first person to solve a specific problem. There are four options today:

  • Cart and Checkout Validation API
  • Cart Transform API (Beta)
  • Shipping Discount API
  • Order Routing Location Rule API

The Cart and Checkout Validation API will enable a store to gate orders to proceed by applying validation to them. This can be powerful for brands that have product limitations, like scarce inventory, limited drops, or products that should only be available to certain customer segments. Think of it as this: what needs to be true for this order to be let through, or what can’t be true for it to be let through? Does the customer require a customer membership, provide a specific digital token (tokengating), or do they need to verify their age? Are they allowed to have at most 4 of a specific product or a cart value of at most $1,000? If a cart doesn’t pass the validation, buyers will see a banner explaining why they can’t complete the purchase. Shopify will eventually provide more flexibility around where a Function can display such validation messages.

The Cart Transform API will make it easier to build cart experiences that better represent the relationship between items in the cart. Instead of showing several line items, you can show them as a single bundle, or show the individual items of a bundle. You can also show Buy One Get One items on a single line, or add and display a free gift. Once the Cart Transform API is promoted to general availability, functions built with this will run every time the cart is updated. This will enable brands to match what the cart displays with how they present relationships between products to buyers, and how they want buyers to think about them.

The Shipping Discount API is similar to previously mentioned discount Function APIs. It allows you to automatically apply discounts to shipping rates at checkout; e.g. offer free shipping, or discounted shipping such as $10 or 15% off. Shipping costs – specifically “surprise” costs – can be a common reason for why buyers abandon their cart. By automating discount logic in this crucial step, merchants may be able to lower the bar for buyers to pass this hurdle and complete their purchase. 

Last and perhaps most niche of the current Function APIs is the Order Routing Location Rule API, likely only useful for some larger merchants that have multiple distribution locations. With this function, you can ‘route’ where line items of an order should be fulfilled from by ranking the order of locations the logic should choose from. You can even deprioritize a location if it already reached a set limit of orders for the day. With this, you can make decisions based on current spare fulfillment capacity or which location is closest to a buyer. Note that if this is what you want to build with, you’re required to email Shopify to gain access. 

Languages and limitations

Once you’ve decided which Function API you’ll build with, we strongly recommend that you read Shopify’s documentation for it, because there may be limitations of when or how it will work. Examples include when the buyer is using Shop Pay, renaming payment methods that have logos, and limitations on modifying delivery options. 

Shopify has also put some other limitations in place. The most important ones are that Functions need to be deterministic, which means you can’t introduce randomness and the same input always produces the same output, they must execute within 5ms, and a function’s output can’t exceed 20kb. 

The limitations are there primarily to guarantee that the buyer experience is not negatively impacted by slow loading, and that Shopify can run the Functions at scale. In a Functions AMA, Shopify PMs have stated that they plan on moving towards a fuel-based system for measuring function performance, as execution time can differ when the same function is run on different hardware.

To build Functions you can use almost any language that compiles down to WebAssembly (Wasm), such as AssemblyScript or Rust. But not all languages are equal. Rust was for a long time the language of choice on Shopify’s end, which means that their tutorials and tooling were primarily Rust. One reason was that the compiled .wasm file needs to be under Shopify’s size limit which as of writing is 256kB, it was hard to achieve with e.g. JavaScript. But in April 2023 Shopify announced the general availability of JavaScript support for Functions APIs, and has added documentation and tutorials for how to build Functions with JS. 

Let’s skip the talk, and start developing! 

Once you’ve figured out a Functions API endpoint and language you want to build with, how do you start building? Follow our example workflow to get started, and feel free to adjust along the way. We also recommend taking a look at Shopify’s suggestions.

To create a Shopify app that uses Functions you’ll need to use Shopify’s CLI. Create your app, then generate the function extension. The CLI will prompt you to select an extension upfront, so you need to know what function you want to build before you start building! After picking a Function API, you will be prompted to select either Wasm or Rust.

Choose which Functions API you want to use.

Selecting Wasm gives you a new extension folder in your CLI app and sets up some basic scaffolding in the form of GraphQL files that define the input and schema of the function. If you pick Rust you get the same GraphQL files, but Shopify also automatically imports some useful Rust packages (in Cargo.toml), sets up build commands in the shopify.function.extension.toml file, and gives yous main.rs and tests.rs files that act as a starting place for function development.

Choose which language you want to build with.

If you are building in Rust, a good first step is to make sure that the default scaffolding works as expected. After installing Rust on your computer, you can simply run cargo test from the function extension root folder to install all dependencies and run the default test.

If you have decided to build in a language other than Rust, you’ll need to do a few things:

  1. Build your own function scaffolding that can read from STDIN and write to STDOUT using the WebAssembly System Interface (WASI). (You can test your function scaffolding with Shopify’s function-runner CLI. Here’s a quick example using AssemblyScript.)
  2. Make sure you can deserialize your function input and serialize your function output.
  3. Write a build command that compiles your function code down to a Wasm file. 
  4. Add that build command to the <inline-code>shopify.function.extension.toml<inline-code> file included in your extension folder. This ensures that your function code will be compiled down to Wasm when you run the deploy command from the Shopify CLI.

Shopify plans on integrating function-runner right into the Shopify CLI so that function testing can be done without loading a separate tool.

Next, think about what your function output should look like, and what input you need to make it happen. Shopify’s Function input and output documentation is invaluable in this step, so make sure to read it. The deterministic nature of Functions make this a great opportunity to follow test-driven development. Write out your unit tests first with the input and expected output, then write your function code to ensure that your tests pass.

Reading Shopify’s guides for a specific Function API will also help you capture any specific context, or learn how to test it in practice. You’ll find it under the Getting Started section in their Functions API docs, where they provide step-by-step instructions, sample code, and descriptions of where in the Shopify Admin to choose, configure, or enable a specific function. 

Another useful tip: Functions also have a page in the Partner dashboard (in the Extensions tab of your Shopify app) where you can review your function’s performance; how many times has it run, how often it exceeds the 5ms time limit, what the function input and output are when it runs, and more. This is useful to debug or monitor your function both during development, as well as when it’s in the hands of merchants. If your function fails to run, you can use the provided function input to add another test to your extension and fix the issue.

We hope you found this deep-dive useful. If you want to get started with Shopify Functions but don’t already have an idea in mind, watch our workshop on Shopify functions and extensions. By the end of it, you should be better prepared to tackle any functions ideas you may have. 

If you have any questions about Shopify Functions, or how to get started building with them, pop into our developer Discord community. We’d be happy to help!

Interested in learning more about Gadget?

Join leading agencies making the switch to Gadget and experience the difference a full-stack platform can make.