Building a full ecommerce site part 4: integrating Paypal checkout express into Django-Oscar

Update 18 Apr 2018: Checkout Express doesn't automatically log customers out after payment. As far as I know, and according to this issue, there is presently no solution. What a nightmare scenario. Take this into consideration if you still want to use it.

Finally, the one thing I was super concerned about: payments. But first, a preamble. Or pre-ramble, if you like.

Step 1: why PayPal's checkout.js and not django-oscar-paypal

I tried out the django-oscar-paypal package and really liked how it added a tab to the Oscar dashboard where you can track all the PayPal payments coming in.

However, I wasn't sure if it was up to date based on its latest GitHub commits and its documentation.

For instance, the documentation on Payflo Pro says, "Unlike Express Checkout, it doesn’t require redirecting the user to PayPal’s site and allows a customer to use a normal bankcard instead of their PayPal account".

But, as of this writing, PayPal Express Checkout does allow it: "Express Checkout... lets [buyers] use their PayPal balance, bank account, or credit card to pay without sharing or entering any sensitive information on your site". More here (requires logging into a developer account).

I'm a bit nervous when it comes to payment gateways and their security, and maybe doubly so since I'm still quite the noob at it. So, I decided to cut straight to the source and use PayPal's own code for payments.

If you do go this same path, you're going to miss out on that sweet Oscar dashboard PayPal tab too.

Step 2: sign up for a PayPal developer account

As of this writing, it's at If you already have a personal PayPal account, I suggest signing up for the dev account using another email, not linked to the personal account. I don't know if it really matters but I'm concerned that I might press the wrong button or something and then suddenly I'd accidentally charged myself some stupid random fee while testing out a client's project.

Step 3: prepare templates for Checkout Express

In an earlier part of this series, I copied Oscar's templates into mezzanine_plus_oscar/shop/templates/shop/oscar for convenience only. I've already copied some of Oscar's app templates out and put them to use in mezzanine_plus_oscar/shop/templates/shop too.

Now, copy the checkout app templates, directory and all, from mezzanine_plus_oscar/shop/templates/shop/oscar and put them in mezzanine_plus_oscar/shop/templates/shop.

Go to mezzanine_plus_oscar/shop/templates/shop/checkout and create paypal_checkout_express.html in it. We'll fill it up with PayPal's JavaScript soon.

Now, open mezzanine_plus_oscar/shop/templates/shop/checkout/preview.html and do the comments in bold.

{% block place_order %}

<!-- Comment out the whole form below to get rid of the "Place Order" button. -->

<!-- <form method="post" action="{% url 'checkout:preview' %}" id="place_order_form">
{% csrf_token %}
<input type="hidden" name="action" value="place_order" />

{% comment %}
When submitting sensitive data on the payment details page (eg a bankcard)
we don't want to save the data and so we pass the bound form to the preview
template and render it in a hidden div. Then the payment information will
get re-submitted when the user confirms the order.
{% endcomment %}
<div style="display:none">
{% block hiddenforms %}{% endblock %}

<div class="form-group clearfix">
<div class="row">
<div class="col-sm-3 col-sm-offset-9">
<button id='place-order' type="submit" class="btn btn-primary btn-lg btn-block" data-loading-text="{% trans 'Submitting...' %}">{% trans "Place order" %}</button>
</form> -->

<!-- Add the code below to add the Checkout Express button. -->

<div class="form-group clearfix">
<div class="row">
<div class="col-sm-3 col-sm-offset-9">
{% include "checkout/paypal_checkout_express.html" %}

{% endblock place_order %}

Step 4: start integrating

PayPal has a lot of broken links on its website but as of this writing, you should go to the page called PayPal Express Checkout Integration. I usually access it by going to the PayPal dev front page and clicking on the big Express Checkout logo and link there. This might change in future.

On the menu on the left, go to Get Started > Add the PayPal Button. Read it through just to familiarise yourself with it. Then click on Set Up a Payment.

It gives you three options: Client-side REST integration, Braintree SDK, and Server-Side REST. Choose Client-side REST integration. This is the easiest way to do it.

Follow the instructions to get your client ID.

Copy the JavaScript code under "Set up your client". Open paypal_express_checkout.html with your favourite IDE and paste the script there.

Step 5: edit the script

You'll see this in the script.

        client: {
            sandbox:    'xxxxxxxxx',
            // production: 'xxxxxxxxx'

I've commented out production for now. You might want to as well. To find sandbox client ID, go to: PayPal developer account Dashboard > My Apps & Credentials > REST API apps > the app you created.

You'll see your Client ID under SANDBOX API CREDENTIALS. Put it into the script.

Next, look at the payment portion.

        payment: function(data, actions) {
            return actions.payment.create({
                payment: {
                    transactions: [
                            amount: { total: '1.00', currency: 'USD' }

Edit away 1.00 and USD like this:

transactions: [
amount: { total: '{{ order_total.incl_tax }}', currency: '{{ basket.currency }}' }

I found these bits of code by following the code trail through the templates. If you want to look at it, it's in a template for the basket app: basket/partials/basket_totals.html.

This allows the total price inclusive of taxes, and the right currency, to load within Checkout Express.

Next, look for this in the script:

        onAuthorize: function(data, actions) {
            return actions.payment.execute().then(function(payment) {

                // The payment is complete!
                // You can now show a confirmation message to the customer

Replace the comments with window.location = "http://localhost:8000";. This way, once the payment is done, the browser will be sent to the home page.

You may want to set it to some Thank You page or other. I haven't decided where I want to send the user yet so I used the home page just for testing purposes.

That's it. The PayPal Checkout Express button will show up at localhost:8000/checkout/preview. A little PayPal window will pop up whenever a guest clicks on it.

Step 6: test it

You'll need sandbox accounts to test it. Go to: PayPal developer account Dashboard > Sandbox > Accounts. Create a sandbox business account and a sandbox personal account. Open them up to see the details. You should have made-up visa numbers and phone numbers and maybe a couple of other things in them.

Now, go to your ecommerce site, upload some products, and test it using these sandbox details!

Step 7: hide the Client ID

We placed our Client ID in paypal_checkout_express.html in Step 5. That would be problematic if we push our code to GitHub or want to show it to people. So, I've created a template in the same folder called paypal_client_id.html and placed the ID in it. There is nothing in this file except fo the Client ID.

Next, I edited the code in paypal_checkout_express.html to include this file:

client: {
sandbox: '{% include "checkout/paypal_client_id.html" %}',
// production: '<insert production client id>'


Finally, I added paypal_client_id.html to .gitignore, which we get in our root directory when we run git init.


Step 8: customise it

Back at the PayPal Express Checkout Integration page, you can find a link to Customize Checkout Button. Here, you'll find out how to make it look nice and sexy.

There are also more important things. For instance, if you click on Best Practices under Reference on the same page, it'll bring you to its Best Practices Guide. Under "Buyer checkout experience and flow", there's a section called "Handle insufficient funds error", which leads you to a section called "Redirect for an alternate funding source".

I believe the "Redirect for an alternate funding source" section is very important, but I don't know JavaScript, so I can't explain how to edit the code in this section right now. Hopefully, someone will, because I need it myself. Please message me if you want to fill in this gap, whether on your site or here.

All right, then. We're done for the day! :D


Comment awaiting approval 1 year, 11 months ago

Comment deleted 1 year, 8 months ago

Comment awaiting approval 1 year, 6 months ago

Comment awaiting approval 1 year, 6 months ago

Comment awaiting approval 1 year, 3 months ago

Comment awaiting approval 1 year, 2 months ago

Comment awaiting approval 9 months, 1 week ago

New Comment


required (not published)