Creating your own shipping rate calculator for Shopify

There are a lot of shipping calculators on the Shopify App Store, but after trying a few out, I learned that none of them could do exactly what I wanted. So I decided to build my own.

NOTE: Unless you’re shipping USPS Media Mail, I would expect that you’d be able to find something in the Shopify App Store that would work for you. My very particular use case wasn’t covered by any existing apps, which is why I built my own.

I have a Rails app running on Heroku that handles a lot of small tasks for me. It connects several services I use, like Shopify, Drip, Zendesk, SyncSumo, and even a local 3PL company in Provo, UT that handles all my fulfillment. The app keeps expanding, and now also acts as a shipping calculator.

Overview of the CarrierService API

A custom shipping calculator relies on the CarrierService API, which, according to Shopify’s documentation, is only available to stores on the Advanced plan. This is a little misleading, because it’s actually availably to any store that has access to real-time carrier-calculated shipping rates, whether that store is on the Advanced plan or not. Last I checked, even if you’re on a month-to-month Basic plan, you can contact Shopify support and add real-time rates à la carte for a few extra bucks a month. Prepaying for a full year will get you the feature for free.

UPDATE: As of Feb 22, 2017, all stores in the US and Canada have access to calculated rates for USPS and Canada Post via Shopify Shipping. Click here to read more.

Once you have real-time rates enabled on your store, you can start using the CarrierService API. You register an endpoint (that belongs to your app) with Shopify that Shopify hit each time it needs some shipping rates (when someone is checking out). Shopify will send your app endpoint the cart contents, along with enough origin and destination information to get quotes from the carriers.

From there, it’s your job to then take that information, get the quotes from the carriers, and return it back to Shopify in a format it can read and display during checkout. Generally speaking, not too crazy.


Shopify uses ActiveShipping to power their own carrier-rate calculations in production, and they’ve chunked it out into a standalone gem you can use in your own projects.

The main purpose of this library is to talk to the different carrier services and return rates. This is obviously a nice thing to have because it means you don’t have to go out and write code to talk to each carrier individually. They’ve abstracted all that complexity into a nice library for you to use.

Once you set up the keys, tokens, and other authentication variables needed for each individual provider (a one-time thing), you just instantiate the class for the specific carrier service you want to talk to, and call `find_rates` while passing it the info Shopify sent you (origin, destination, and cart contents). The basic call looks like this:

response = usps.find_rates(@origin, @destination, @package)

Pretty nice, right? Then you just parse through the response to generate the object Shopify needs to be able to show the rates during checkout:

rates = response.rates.sort_by(&:price).collect {|rate| {
service_name: rate.service_name,
total_price: rate.price,
service_code: rate.service_code,
description: rate.description,
currency: rate.currency

Showing rates based on cart contents

So far, this setup would just return all USPS rates, even if they didn’t apply to your order. For example, it’ll return Library Mail and Media Mail if you’re shipping domestic. Library Mail is only for stuff sent between libraries, and media mail is only for things like books, CDs, DVDs, printed music, etc.

Lucky for me, I can use Media Mail for a majority of shipments because most of what I’m shipping are books. It’s a relatively cheap way to ship (usually around $2.67 to ship our heaviest book), and I offer it free to people in the US. It takes 2-8 business days, but some people are willing to wait if it means FREE. (I also offer the chance to upgrade to Priority for a flat fee–more on that later.)

But not all orders qualify for Media Mail. For example, if someone buys a book and a cross-stitch starter kit, the shipment is no longer eligible for Media Mail shipping.

A lot of the Shopify Apps allow you to customize rates shown based on cart contents. That’s not new. The reason I built my own shipping calculator is because none of those apps would also let me include Media Mail as a shipping option.

Filtering rates based on products

Once I return rates from the carriers, I send them through a few filters to make sure I’m only showing the rates I want to show. I have two main filters that the rates run through before being sent to Shopify:

Media Mail Filter

Like I said earlier, orders only quality for Media Mail shipping if they consist entirely of Media Mail eligible materials. I have an array of product IDs (stored as ENV variables) for each of the products that are Media Mail eligible. This filter runs through each product in the cart, and if any of them do not appear in the array of approved products, Media Mail is removed as an option.

Approved Shipping Rates Filter

I’m a huge believer in the Paradox of Choice, so I don’t show every rate that comes back. Just like I have an approved list of product IDs that are eligible for Media Mail, I have an approved list of shipping rates I want to provide, stored in an array. The list of rates returned by the carrier is run through this filter, which removes any rate that isn’t on my approved list (like Library Mail).

Promotions Filter

The last filter is one that applies any shipping promotions I’d like to offer. For example, if someone wants to upgrade from Media Mail shipping to Priority shipping, that’s an option. But I don’t charge them the full cost of Priority, since I’m already willing to eat the shipping cost of the Media Mail. This filter takes rates like the Priority rate and can either reduce it or make it a flat fee instead. If I wanted to, I could reduce the Priority rate by the exact amount that Media Mail would cost. For now, I just offer a flat fee.

Once the rates pass through these filters, the surviving rates are passed back to Shopify (they were formatted properly for Shopify when we parsed through the carrier responses earlier) and displayed during checkout.

This Post Has One Comment

  1. Hello,
    Thank you for posting this. I am really interested in adding Media Mail for my customers to see a rate. I read through your article several times, but I am honestly, not very tech savy, so I was not able to get beyond adding the carrier service API. Would it be possible to get a step by step of how to do it. Thank you.

Leave a Reply

Close Menu