Creating a Shopify Proxy App with Django: A Step-by-Step Guide
, 8 min reading time
, 8 min reading time
In this blog post we'll go over how to add custom functionality to your Shopify store using Django and proxy apps. Shopify proxy apps give developers the ability to add dynamic content by redirecting users to external links while still appearing under your Shopify domain.
I'll be focusing on developers that want to extend their store functionality vs. developers that want to make a custom app to sell to multiple shop owners. However, some of the information here might be relevant for both. This guide will focus on the backend server side. If you are interested in creating an app that integrates with the Shopify Admin interface, take a look at App Bridge.
Here are a few potential uses case why you might need a proxy app:
This is the basic flow for a proxy app. All of this is transparent to the user.
Shopify has a sample application for Django, however it hasn't been updated in years and doesn't implement all of the functionality described above. In fact, there is no HMAC verification meaning anyone can navigate directly to your proxy server and spoof requests. We've added this functionality in our forked version.
Download the code and setup the environment
git clone git@github.com:ScalpRadar/sample-django-app.git
cd sample-django-app/
python -m venv .venv
.venv/bin/activate
Go to https://partners.shopify.com and login with your shopify account.
Navigate to the "Apps" section and click "Create App".
Now that we've seen the admin page, let's take a look at the page visible by customers. Login to your store as a customer. Then navigate to APP_URL.myshopify.com/apps/p/ (or whatever your app suffix is). You should see a basic welcome page with the logged in customers ID and a form that echos content back to the user.
This page can contain anything you wish your logged in users to see. In Scalp Radar's case, this is where customers manager their software licenses.
Let's take a look at how everything works. These are the following Django apps
sample_django_app: Main Django app. Contains the URL routes and settings.py
home: Contains application views and models for proxy and admin page.
api: APIs for javascript to query info about the store. This came with the original sample app and is currently unsued.
shopify_app: Contains all of the logic for HMAC verification and app installation.
Let's take a look at the view code in home/views.py
This view handles the Shopify proxy requests at /shopify/. Most of the work is done by the decorators, which are found in shopify_app/decorators.py
shopify_hmac_verification: Verifies the signature to make sure Shopify is sending the request.
known_shop_required: Makes sure the shop that sent the request matches the shop this app was installed in.
latest_access_scopes_required: Checks if the app needs to be reinstalled if the access permissions have changed
csrf_exempt: Disable Djangos cross-site request forgery protection because it relies on cookies which are stripped by Shopify. HMAC verification makes up for this.
The rest of the GET and POST request code is pretty standard.
Let's take a look at the signature verification in shopify_app/decorators.py
Shopify signs the HTTP parameters it sends us with the apps secret key. This code verifies the signature and checks that the timestamp is not too far in the past. The latter is to prevent replay attacks.
Here is what the request URL from Shopify looks like.
/shopify/?shop=example.myshopify.com&logged_in_customer_id=1234&path_prefix=%2Fapps%2Fp×tamp=1720561758&signature=xxxxxx
The only complication is Shopify appears to calculate the signature differently for requests coming from the admin interface and from the external proxy page so we handle that here.
POST requests from the admin page, like 'sync orders' button, don't have parameters. Instead we need to look at the HTTP referer. That contains the URL and parameters that were used to load the admin page, similar to the URL above. The problem here is the timestamp may be old depending on how long the admin page has been open before the POST request is sent. I provide some alternative solutions in the code comment.
While we've tried to improve the Shopiyf Django app, there are still a few things that need work.
Shopify can be a great platform to build dynamic web apps without having to implement all of the e-commerce logic. I hope this guide and sample code helps speed up your development process.