Selling Digital Products on Shopify

I’m on my third digital delivery app for Stitch People, and I think I’ve finally found something that’ll work for me: SkyPilot. Here’s a review of what it does, why I like it, and why the other things I’ve tried have failed.



This is my current app. I made the switch final today (May 15, 2016) and things are now running smoothly. Here’s what I love about it:

  • While the actual files are hosted and served through, this is all done behind the scenes and masked through your own domain. When people click on the link to download their file, the link is your domain. The SkyPilot app then intercepts that request and serves the necessary file.
  • The entire experience is on my domain. SkyPilot gives you templates to manage, so you have full control over how the experience looks for your customers. It integrates into your existing theme and layout, so there’s no break in the visual experience for your customers.
  • It integrates into the order status page. When someone completes their order and it contains digital products, they’ll see a button on the order status page that takes them to another page (on my domain) that lets the customer download the file. I still send a follow-up email (see the next point), but that’s now a backup. People can immediately download their files after their purchase without having to go back to their inbox and wait for a link.
  • I can manage the email notifications entirely. I’ve turned off email notifications through SkyPilot, and instead I send the download links through my email marketing service, Drip. When someone orders something through Shopify, Drip is notified and stores the customer ID. I then use that customer ID to generate their unique download link and send it to them. All emails go through my domain and have the highest deliverability rates possible. No more lost notification emails.

I’m hoping that I’ll stick with this one for a while. So far, it has everything I want, lets me see how many times someone has downloaded a file, logs the IP address of each download, and gives me the flexibility I want to craft the entire experience.



This was the second app I used, after Digital Downloads (below). It worked well for about 6 months, but eventually three things made me start looking for a third option.

  • The email notification sent to customers through SendOwl is sent from They don’t have support for sending emails through your own domain, so even though I was able to set the ‘From’ name on the email, a lot of the download notification emails were going to customers’ spam folders. Not good.
  • Files were all hosted and downloaded directly on While they do offer some branding options, customers are ultimately leaving your site to go download their products elsewhere. This never really sat right with me.
  • Sometimes, customers would receive the email with the link, click on the link, and get a 404 error from SendOwl. Usually this resolved itself if the customer tried again in a few minutes, but this was completely unacceptable for me. A huge selling point to offering digital products it the immediate satisfaction a customer gets when they purchase and then download the file. A service that can’t reliably deliver a seamless experience isn’t worth my time.

Digital Downloads by Shopify


This was the first app I used and it’s been probably 8 months since I’ve used it, but based on my experience, I have no desire to try it again. For me, the biggest issue was the inconsistencies with the download limit feature (which limits the number of times a customer can download a file). The default had it set to 3, and I kept getting emails from frustrated customers saying that the first time they clicked the link, they were told that they had exceeded the number of allowed downloads. I was going in at least once a day to reset someone’s download limit.

Another thing that drove me crazy: all downloads logged the IP address that download came from. Problem was, all downloads were being attributed to an IP address associated with Shopify. I emailed the Shopify team about this, and they confirmed that this was happening with every store that had the app installed. Several months after alerting them to the issue, it still hadn’t been fixed. Between this and the download limit weirdness, I decided that this app wasn’t worth the headache.

Accessing transaction data in a Shopify email notification

Recently I needed to add a line to the Shopify Order Confirmation email that included the last 4 digits of the credit card used. This was more difficult than it needed to be, so I’m writing this post in hopes it’ll rise to the top in Google and help others trying to do the same thing.


You need to access the transaction object through a collection of transactions, like so:

{% for transaction in transactions %}
{{ transaction.payment_details.credit_card_number }}
{% endfor %}

This was stupidly difficult to track down. First, I went to the email variables article that’s referenced when you’re editing a notification. There, it states:

Notifications have access to every transaction property. Please see our Transaction API documentation here for a full list of the properties.

So I checked out that article, which didn’t help at all. Dead end.

After a few more searches, I finally found this thread in the forums that addressed my problem exactly. Reading through some of the comments, I thought I had hit another dead end, until I read the last comment in the thread, which pointed me to the thread that answered my question. Thanks to Mikkel Jakobsen for tracking down the answer!

Tagging past Shopify customers in ConvertKit via API

We’ve recently started using ConvertKit for our email marketing for Stitch People, and I LOVE IT. It’s flexible, easy to create automation sequences (called courses), easy to move people in and out of courses based on any number of events (purchase, link click in an email, etc.), easy to tell exactly which form someone signed up on, and much more.
The first step in my migration to ConvertKit was to start collecting new subscribers and customers into ConvertKit, and to tag them automatically for easy segmentation later. This included writing a small Shopify app to automatically subscribe customers and tag them based on what they purchased. I’ll write another post about this later.

Once all new subscribers were being funneled into ConvertKit instead of Mailchimp, it was time to clean up old data. The first place I started was to tag past Shopify customers based on the product they purchased. We have a relatively small number of products right now (different variants of a book is our main product), but this would work just as well for a large catalog of products and customers.

To do this, I’ll be using the ConvertKit API (documentation found here).

Step 1: Create the tags in ConvertKit

The main API endpoint we’re going to be hitting is the Add Subscriber to Tag endpoint. And since the API doesn’t support creating new tags yet, you’ll need to create these tags through the website first. Head to the Subscribers area, and click ‘Create Tag’ at the bottom of the right sidebar. That’ll bring up the box to create a new tag.

convertkit tag creation

You can come up with your own naming convention for tags, but my general rule of thumb is to be descriptive. You may know what an obscure tag means when you create it right now, but your 6-months-from-now self won’t, and you’ll kick yourself when you have a bunch of people tagged, but you don’t know why.

For example, I use tags like ‘diy-physical-book’ and ‘diy-ebook’ to differentiate between two different variants of the DIY Stitch People book. I prefixed it with ‘diy’ because we’ll be releasing more books later, for which we will have physical and digital copies. For those, I’ll create tags like ‘farm-animals-physical-book’ and ‘zoo-animals-ebook’. These will be easy to decipher down the road.

Step 2: Grab your list of customers from Shopify

Next, head to Shopify and do an export of all your orders. Head to the Orders tab, and hit the Export button at the top. Make sure you select the All Orders radio button, and export the orders, not transaction histories. I use the CSV for Excel, Numbers, etc. option. I’ll eventually be uploading this to Google Drive.

shopify order export

Step 3: Make separate lists of email addresses for each tag

This will likely be the most time-intensive step in this whole process. Now you need to take the CSV from Shopify and filter through several times to generate lists of email address for each tag you want to apply. For me, I created three lists: one for physical book purchasers, one for ebook purchases, and one for physical + ebook purchases. These are the three tags I’m using, and now I need to come up with three separate lists of email addresses–one for each tag.

For this step, I used Google Spreadsheets. You could also use Excel, Numbers, or any other spreadsheet program that lets you quickly and easily filter your table based on column contents. Once you have your CSV file loaded in whatever application you’re using, you need to filter the table by products/variants. In Google Spreadsheets, you can use the Filter feature and then select the ‘lineitem_name’. In my case, I’ve been through several different iterations of the product and variation titles, so for my ebook DIY book buyers, I had to select several values:

filtering lineitem_name

Once filtered, copy those email address and throw them into a new tab in the spreadsheet. Make sure you label the tab so you know which list you have. Repeat this step for any other tags you want to apply.

Step 4: Write the script to tag the subscribers

Now comes the fun part. You can choose whatever language you want, as long as you have a way to make an HTTP POST request. I chose Ruby and used Faraday. Here’s a gist:

First thing you’ll want to do is populate the arrays of email addresses. Take the email address lists from your individual spreadsheet tabs and format them as strings in an array. I used a text editor (Atom) to quickly do this, then just pasted in the result. I was dealing with about 2,000 email addresses total.

Once you’ve created the arrays, head to your ConvertKit account page to find your API key. Put that value in.

Finally, you’ll need to grab your ConvertKit tag ids and populate those into the URL strings. Head to ConvertKit, click on the tag you want, and grab the ID from the URL:

tag url

Put that value in for the XXXX between ‘tags’ and ‘subscribe’ for each tag.

Step 5: Run the script

Now it’s time for the magic. Save the file you’ve been editing and then run it. For Ruby, I just opened a terminal window, navigated to the folder where the file was, and typed ‘ruby filename.rb’ to run it. Mine took about 10 minutes to run to completion. Once that was done, all my subscribers were properly tagged with the product they had purchased, allowing me to create Courses and Segments based on those tagged subscribers.

CSS Framework for Shopify Embedded Apps

I’ve been working on a custom Shopify app for our Stitch People store and was recently looking for a way to make my app look like the rest of the Shopify admin area. Using the Embedded App SDK (EASDK), introduced in February 2014, the app gets loaded within an iframe, sandboxing the whole thing from Shopify’s styles and other assets. After looking around the forums a bit, the only thing I found was a short outdated thread about CSS, with no resolution. It mentions the possibility of a Widget Kit, but I haven’t been able to find anything else on the subject.
I did come across a project on Github–the Shopify Embedded App Frontend Framework by microapps, a Shopify dev shop with a few successful apps already in the store. It has several files and a few directories, but the only file to worry about is the seaff.css file. Include it in your app and then look at docs.html for some examples on how to use the framework. So far so good for me. I haven’t used all the different elements yet, but what I have used has looked great. If you’re building a Shopify app, I’d definitely give it a look.

Shipping a physical product

I never thought I’d be in the business of shipping a physical product. As a freelance developer, I always thought I would only ever offer services, or at most, a digital product like an e-book. So when my wife self-published the DIY Stitch People book, we had to figure out how to get those books from point A to point B.
When we first started selling the book, we didn’t have any sort of system set up. When we needed to ship a book, we’d go to a local place that handles everything from packaging to shipping. We’d buy a padded envelope, stick the book in, seal it, and then head to the front counter and read back the name and address of the customer while the person on the other side of the counter typed it in and generated a label. Then that person stuck the label to the envelope, threw it in a pile with other outgoing mail, and we paid for the envelope and postage.

This process sucked, especially when we had to ship out over 50 pre-orders at once. We were at the store for about 2 hours, and the receipt we got at the end was super long. Here’s a picture of the nice employee holding our receipt:

Stitch People Receipt

On that receipt were the tracking numbers for each package, too. So we went home and typed in each tracking number for each order and sent the customer their shipping confirmation email.

Lizzy and I quickly realized that this process wasn’t going to work. It was time-consuming, expensive, and error-prone. First, we found padded envelopes online at ULINE. Buying in bulk online was definitely cheaper than buying individual envelopes in the store. Problem solved (or so we thought–more on this later).

Next, we looked for a way to generate labels at home. That way, we wouldn’t have to spend so much time at the store reading off the names and addresses of each customer. We love podcasts, so we’d heard a lot about We signed up and started generating labels at home.

With our new envelopes and the ability to generate our own shipping labels, the next iteration of our shipping process was set. When an order came in, we’d throw a book into a ULINE envelope, go to, copy and paste all the customer information, generate the label, print it out, and tape it to the front of the envelope. Then we’d copy the tracking number and paste it into Shopify, which would send the customer their shipping confirmation email. And because we were using USPS (Media Mail, because we’re shipping books), we could leave the envelopes for our mailman to pick up, so we didn’t have to leave the house to ship. Not a bad improvement.

But this process got cumbersome after a while, too. The copying and pasting from Shopify to wasn’t very slick, and we were still making a few mistakes every now and then when generating labels. We figured that since the customer information was already in Shopify, there had to be a way to easily generate the label and update the order with tracking info without copying and pasting. So I went in search of another solution and landed on ShipStation.

I’ve written about ShipStation (and some of this other stuff) already in another post. It’s a really great solution and is what we currently use. When an order comes in, we go to ShipStation, where I’ve created presets for all the different options for shipping that we use and offer customers (international, media mail, priority, etc). It pulls the order data in from Shopify, we apply a preset, and then generate and print the label. As soon as the label is generated in ShipStation, it sends the tracking number back to Shopify, and the customer is sent their shipping confirmation email. Another big improvement.

When we first started using ShipStation, we were still printing labels on regular paper with our ink printer. It worked, but it was a hassle. The labels we generated were 4×6, not 8.5×11, so we were wasting a lot of paper. And taping labels to the front of the envelope sucked. Lizzy’s mom (who helps with fulfillment) suggested we look at a thermal label printer that worked with ShipStation. We found the Dymo LabelWriter 4XL on Amazon.

DYMO LabelWriter 4XL

With this thing and some cheap generic labels, things got really easy. Now we could process a batch of labels in ShipStation, the tracking numbers would get sent back to Shopify, and we could print on sticky labels without needing ink. The thermal-printed labels (the exact size of the generated label) just peel off and stick right to the package. This was a HUGE improvement for us.

The most recent thing we changed was the envelopes. We were getting complaints from customers that the packages were being mutilated in transit, arriving bent and creased. First we tried contacting USPS about it and learned that there’s nothing they can do. With Media Mail especially, our packages were being tossed around with much bigger and heavier packages. If we wanted to keep using USPS (they’re the cheapest option for us), we’d need to look at new packaging.

I checked out the ULINE catalog and found their Easy Folder Mailer boxes which work perfectly. It’s a tight fit because our book is spiral bound, but it protects the book so much better than the envelopes. It’s a bit more work to put the book into one of these things, but since we started using the boxes, we haven’t had a single complaint about the condition of the book when it arrives. For us, it’s definitely worth it.

And that’s where we are today. When an order comes in, we grab a box, fold it around the book, tape it shut, go to ShipStation, print out the label, slap it on the front, and leave it for the mailman. ShipStation talks to Shopify and sends over the tracking number, which is automatically sent to the customer. It’s not a perfect system, but we’ve found a nice rhythm to our shipping process. And I’m sure we’ll find other ways to improve as the need arises.

Do you ship a physical product? What would you suggest we do differently?