Direct Sales Integration with Lemon Squeezy on a Middleman Site
I've found a cool way to set up direct sales on your own website with minimal effort and basically no coding. But my personal website is all hand-coded by me, and so I decided to take it one step further and integrate it with Middleman and how I use the yaml files to keep my website organized as my catalog grows. Read on to learn more about my setup combining Lemon Squeezy's Checkout Overlays with yaml and ERB in my favorite static site generator, Middleman.
The Backstory
I've been looking for a better way to do direct sales, as Amazon, IngramSpark, and other book distributors and publishers keep reaching their hands further into the author's pockets. I've unfortunately had to raise the prices on my books so that I would not end up owing money to these companies. They keep inserting new fees or raising the amounts on existing fees. Even if they still advertise “70% of royalties,” that comes after they take out delivery fees based on the size of your eBook. There was a hubbub back in August when IngramSpark forced authors to take a lower cut of the profit by up to 15%. I had to raise the prices, or I would owe money. But I didn't want to raise them too much, so I raised it to the bare minimum. I increased my book price by $3.00 ($9.99 to $12.99) and went from getting $1.17 in royalties to $0.20 in royalties. Yeah.
So, I decided to go on a hunt for a way to sell directly. I started by trying out Gumroad and having a custom domain used on it. But it still took people off-site, and it was still another click a potential reader had to make between finding my book on my homepage and actually having the book in their hands.
I kept looking and found Lemon Squeezy. At first, it seemed like it would be just another storefront that I would have to set up a custom domain for; still one more click, still on a webpage I didn't have full control over. But then I found their Checkout Overlays.
Setting Up
The first thing you'll want to do is set up an account on Lemon Squeezy and create a store. You can have multiple stores for your singular account, but each store will need its own approval to operate. Getting approval isn't hard; just make sure you are following their Terms of Service and aware of what you can/cannot sell! I just filled out some easy questions, and a few hours later, I had an email saying I was approved! While I was waiting, I was able to set up some products in test mode, play around with themes, and check out all the sweet features.
I was able to set up the lemon squeezy storefront to look pretty similar to my own home page, even having a pretty banner. It looked far better than the one on Gumroad.
But was that enough? Was “lower fees and looks prettier” enough for me? No, it wasn't. And that's when I found Checkout Overlays.
Checkout Overlays
Checkout Overlays are what they say on the tin. Overlays. You click on the button, and a lightbox/overlay/popup appears. Blurring out the rest of the page and showing a spot to input payment details.
THAT is what I wanted, but I wanted it on my website. And, wouldn't you know, Lemon Squeezy can do that.
1.) From your Lemon Squeezy dashboard, go to “Design,” and at the top, you will see the option “Overlay”. Click on that, and you can either use your theme style or override it and pick your own colors!
2.) Go to the product you want to sell, and in the corner, there should be a “Share” button.
3.) In these settings, you can select either the checkout page or the checkout overlay. You're gonna want the overlay. You can decide if you want the store logo (if you have one) and many other things. But do you see that it says you can just copy and paste it? Yup. That's it! Copy and paste that bit wherever you want to on your website, and a little button will appear. If it's clicked, that little overlay shows up! Easy peasy! You could easily end your journey here with a sweet checkout process directly on your own website.
4.) BUT... that's not enough for me. I like my code DRY, and I truly try to keep my HTML documents free of copy and unnecessary lines of code. Note that there are a few components to this code that Lemon Squeezy gives you:
<a href="https://daxmurray.lemonsqueezy.com/checkout/buy/ac8af7c7-3d97-4ac3-bab7-4b900605931b?embed=1" class="lemonsqueezy-button">Buy A Lake of Feathers and Moonbeams</a><script src="https://assets.lemonsqueezy.com/lemon.js" defer></script>
- The anchor, which has the url:
https://daxmurray.lemonsqueezy.com/checkout/buy/ac8af7c7-3d97-4ac3-bab7-4b900605931b?embed=1
and the class of"lemon-squeezy-button"
- The embedded javascript:
<script src="https://assets.lemonsqueezy.com/lemon.js" defer></script>
Grab these and put them in your notepad/scratchpad/wherever you keep snippets you want to copy/paste.
5.) I keep all of the copy, image urls, and buy links for my books in a file called books.yaml
in my data
folder in my Middleman project. Example of one book's entry in the books.yaml and the specific line you want to have in order for this to work.
---
- shades-and-silver:
title: "Shades & Silver"
cover_flat: "images/shades-and-silver/shades_and_silver_flat.jpg"
cover_3d: "images/shades-and-silver/shades_and_silver_3d.png"
animated_3d_cover: '<script src="https://3dbook.xyz/api/books/6507d29c45d4d5004a83add5/cover.js"></script>'
intro_hook: "Stories of identity, doubt, and belonging"
main_description: "<p>The birthright of every Ástfríður is to know each metal in the earth, command it, bend it to their desires. To hear metal singing, some of it waiting just beneath the surface, so much of it deeper in the earth. If they wanted, the knew they could pluck that metal from the earth, melt it with a thought, and shape it as they pleased with a breath of air and their will.</p> <p>Each Ástfríður must choose which metal they would wear upon their heads, denoting the path they would walk. They craft beautiful horns to wear on their brow, forged with the metal they wish to identify with. But Britt does not know if they can choose the path they want, if they can overcome a past which has stolen their identity. The day has come for them to choose and they have no idea if they have any right to even try to. And Astrid has never felt the pull of the metal at all Wearing a forged circlet and horn, they try to navigate a world that they feel has rejected them, all the while fearing someone will learn their secret."
exit_hook: "The Veil of the Ástfríður has kept them hidden from the world and safe from intruders. Yet Britt and Astrid feel they are imposters in their own homes. <br/> <br/><p>Get a copy for FREE by <a href='https://newsletter.daxmurray.com'> signing up for my newsletter</a> OR when you purchase <a href='https://stars.daxmurray.com'><i>Stars and Soil</i> on Campfire</a>!</p>"
review: null
purchase_direct: "https://daxmurray.lemonsqueezy.com/checkout/buy/695e727b-c455-4b09-aa75-4a1d1bd4fd0f?embed=1"
purchase_links:
"Gumroad": "https://store.daxmurray.com/l/shades-and-silver"
"Amazon": "https://www.amazon.com/Shades-Silver-Scions-Shadows-Murray-ebook/dp/B08W3R96WJ/"
"Apple": "https://books.apple.com/us/book/shades-and-silver/id1552626521"
"Kobo": "https://www.kobo.com/us/en/ebook/shades-and-silver"
"Everand": "https://www.everand.com/book/493673556/Shades-and-Silver-Scions-and-Shadows-1"
"Smashwords": "https://www.smashwords.com/books/view/1493542?ref="
"Other Stores": "https://books2read.com/shades-and-silver"
link: "/shades-and-silver.html"
slug: shades-and-silver
series_name: "Scions and Shadows"
cover_art:
name: "Merilliza Chan"
link: "https://www.merilliza.com/"
typography:
name: "Mibl Art"
link: "https://miblart.com"
interior_design: null
interior_illustrations: null
editor: null
is_series: !!bool true
scions: !!bool true
standalone: !!bool false
poetry: !!bool false
latest: !!bool false
coming_soon: !!bool false
release_date: "February 12, 2021"
Take note of the field purchase_direct
. I added that field and put in the URL I got from the copy/paste code provided by Lemon Squeezy.
6.) Next, put that line of Javascript into the <head>
of your main layout
file! You can check my full layout file on GitHub, too.
<!-- LEMON SQUEEZY -->
<script src="https://assets.lemonsqueezy.com/lemon.js" defer></script>
7.) This is the cool bit, I promise. I set up my middleman with a few helper methods that call on the boolean fields in my books.yaml
. This isn't something that you have to do, but I wanted to show it off just in case it would be helpful for you, too.
Here's my helper method in the config.rb
helpers do
def get_latest
@app.data.books.each do |b|
if b.latest == true
@latest_release = b
end
end
end
def get_coming_soon
@app.data.books.each do |b|
if b.coming_soon == true
@coming_soon = b
end
end
end
def get_scions_series
@scions_books = Array.new
@app.data.books.each do |book|
if book.scions == true
@scions_books.push(book)
end
end
end
def get_standalones
@standalone_books = Array.new
@app.data.books.each do |book|
if book.standalone == true
@standalone_books.push(book)
end
end
end
def get_poetry
@poetry_books = Array.new
@app.data.books.each do |book|
if book.poetry == true
@poetry_books.push(book)
end
end
end
end
The first helper, get_latest
checks each book in books.yaml
to see if the field latest
is true. If so, it sets a global variable that I can access in the index page with all of the info for that book. This means that when I release a new book and want to update my landing page, all I have to do is set my previous release to false
in the latest
field and add my newest one with the flag for the latest
set to true.
My index/home page uses embedded ruby to fetch @latest
and use books.yaml
to fill it in. You can check out my get_latest
helper method on my GitHub here.
<% get_latest %>
<% get_coming_soon %>
<div class="pure-g home-page">
<div class="pure-u-1 pure-u-lg-1-2 book-card">
<div class="pure-g">
<div class="pure-u-1">
<h1 class="release-type"> Latest Release <h1>
</div>
<div class="pure-u-1">
<h2 class="title-link"><%= link_to(@latest_release.title.to_s, @latest_release.slug) %></h2>
</div>
<div class="pure-u-1">
<h3><%= @latest_release.intro_hook %></h3>
</div>
<div class="pure-u-1">
<!-- <%= image_tag(@latest_release.cover_3d, height: '500', class: "book-card-img") %> -->
<%= @latest_release.animated_3d_cover %>
</div>
<br />
<div class="pure-u-1">
<h3> <%= @latest_release.exit_hook %> </h3>
</div>
<div class="pure-u-1 purchase-button-group">
<% @latest_release.purchase_links.each do |name, link |%>
<%= link_to(name, link, class: "purchase-button") %>
<% end %>
</div>
</div>
</div>
(If you're wondering about some of the html classes here that say pure
in them, they are from the PureCSS, a very lightweight CSS library with a very nice grid system!)
Same deal with get_coming_soon
– I can set up my next release and make sure it's also on my home page. It was a great feeling when I switched STARS AND SOIL from coming soon
to latest
! And here is the Github link for my get_coming_soon
method, too.
The last few helpers here let me snag just my stand-alone books, just my poetry books, or just the books in the SCIONS AND SHADOWs series. Magic, and you can see it on Github, too.
There's so much you can do with helper methods and yaml in Middleman. It's so cool. If you aren't doing any fancy tables or data analysis and just serving up static content, a static site generator is the way to go.
You don't have to do this. But I wanted to share so that you could emulate this if you wanted or apply it to what you already have or use this as inspiration with your MVC framework!
8.) ERB or other templating language MAGIC! On my books index page (books.html.erb
), you can see that I start off by using the get_standalones
and get_scions_series
helpers to pull in my books and have them sorted into the groups I want to display them in. (Github link to just the two lines that grab the variables).
<% get_standalones %>
<% get_scions_series %>
I then iterate over the array of stand-alone books and for each one that I have, it inserts the appropriate information into the template! DRY as heck! It grabs the title, the cover, creates a link to the books individual page. I keep my intro hook, main desription, and exit hook as different fields in the yaml so that I can more easily pick and choose what I want to show and how I want to display it!
<% @standalone_books.each do | book |%>
<div class="pure-u-1 pure-u-md-1-2 pure-u-xxl-1-3 books-cards">
<%= image_tag(book.cover_3d, height: '500', class: "book-card-img") %>
<h2><%= link_to(book.title, book.slug)%></h2>
<h4><%= book.intro_hook %></h4>
<p><%= book.main_description %></p>
<h4><%= book.exit_hook %> </h4>
<div class="pure-u-1 purchase-button-group">
<% if !book.purchase_direct.nil? %>
<div class="pure-u-1 pure-u-md-1-3 pure-u-lg-1-4">
<%= link_to("Buy Now", book.purchase_direct, class:"lemonsqueezy-button direct-purchase-button") %>
</div>
<% end %>
<br/>
<h3>Purchase elsewhere:</h3>
<% book.purchase_links.each do |k, v |%>
<div class="pure-u-1 pure-u-md-1-3 pure-u-lg-1-4"><p><%= link_to(k, v, class: "purchase-button") %></p></div>
<% end %>
</div>
</div>
<% end %>
I specifically want to call out this bit as the magic:
<% if !book.purchase_direct.nil? %>
<div class="pure-u-1 pure-u-md-1-3 pure-u-lg-1-4">
<%= link_to("Buy Now", book.purchase_direct, class:"lemonsqueezy-button direct-purchase-button") %>
</div>
<% end %>
What's going on here? First, I am checking to see if the book has the field purchase_direct
and if so, making sure it's not empty. If it's empty, this bit of code gets skipped. If it didn't get skipped, it would throw an error.
If there is a direct purchase link in the field, it will fill in the link_to
helper using the link that I put into purchase_direct
in my YAML. Additionally, I am passing it the lemonsqueezy-button
CSS class (as well as my own direct-purchase-button class, since I wanted this button to stand out from all of my other purchase buttons!)
And voila!
I also put an if/else statement for if I have other purchase links, and if so, it shows “Purchase Elsewhere,” and then it iterates over the purchase links provided in the books.yaml
.
So pretty! Each book now has a “buy now” button on the page! and clicking on it will display the overlay!
9.) I also use some helpers in config.rb
to make dynamic pages for each of my books, allowing me to use a template for all individual pages for the books and setting up variables. Checkout out this helper method on Github!
config.rb
# dynamic pages for each book
@app.data.books.each do |b|
proxy "/#{b.slug}.html", "/book_page.html", :layout => false, :locals => { :b => b }, :ignore => true
end
book_page.html.erb
<% book = locals[:b] %>
<% @title = "#{book.title} - Dax Murray" %>
Here I am grabbing the variables after the user clicks on the direct link for a book. This also sets the title of the page to use the book title! Nifty!
In this template, I added the same bit of code to check if there is a direct purchase link and display the buttons if so!
<div class="pure-u-1 purchase-button-group">
<% if !book.purchase_direct.nil? %>
<%= link_to("Buy Now", book.purchase_direct, class:"lemonsqueezy-button direct-purchase-button") %>
<% end %>
<br/>
<% if !book.purchase_links.nil? && !book.purchase_direct.nil? %>
<h3>Purchase Elsewhere:</h3>
<% end %>
<% if !book.purchase_links.nil? %>
<div class="purchase-button-group">
<% book.purchase_links.each do |k, v |%>
<div class="pure-u-1 pure-u-sm-1-2 pure-u-md-1-4 pure-u-lg-1-6"><p><%= link_to(k, v, class: "purchase-button") %></p></div>
<% end %>
</div>
Here is the individual book page for BIRTHING ORION, my poetry book about two space goddess! And sure enough, without even leaving that webpage or being redirected to another page, you can click “buy now” and this checkout overlay appears!
Magic! From now on, when I release a new book, all I have to do is grab the link from the lemosqueezy page and paste it into the purchase_direct
field in books.yaml
! My templates will do the rest!
If you use are using an MVC framework or database, do the same thing but make sure the lemon squeezy URL is saved in the database and it passed through the controller/router. But for my tiny website, I am content with a static site and have been using Middleman to run it for years now. I am sure that you could do the same with any other static site generator and templating language.
Other cool things about Lemon Squeezy
Even if you don't intergrate Lemon Squeezy with Checkout Overlays like I have, I still think you should give them a look. Here are some of the other cool things they offer:
- Never worry about international taxes! They handle tax remittance and VAT for you, automatically.
- So many ways to pay: They accept major credit cards, Paypal, Apple Pay, Google Pay, AliPay, WeChat Pay, Afterpay, and so many more! And you get to decide which ones you want to accept!
- Global Currencies: They accept currencies from around the globe, large and small countries. You get the choice of which ones you want to accept!
- Subscriptions: You can sell subscriptions! They help you handle prorated payments, control the billing cycle, and even usage-based billing!
- Create License Keys: Works great with their subscription system!
- Set up free lead magnets or offer Pay What You Want: This is what made me go :eyes: tbh.
- Impressive Roadmap: Looking at their product roadmap, there's a lot that stands out, including an online course builder and upsells!
- Pricing: No monthly charges. They take 5% + $0.50 per transaction. That's it. So much better than what you get selling on Amazon!
There's a whole lot more going on over at Lemon Squeezy. I swear I'm not being paid to say any of this. Check them out, especially if you want to be able to sell directly on your own website, easy peasy!
Umm, I guess you could buy my books?
Even if you don't use Middleman, I hope this tutorial at least gave you some ideas about how to add checkouts directly on your webpage instead of putting even more clicks between the books and your readers—every click you put between them is another opportunity for a reader to give up in frustration.
Speaking of reading, you can purchase my books directly on my website!
Happy writing and selling!
Join my newsletter Subscribe for updates like this and exclusive announcements, bonus content, and more! Sing up today to get a FREE copy of Shades and Silver plus a sneak peek at Smokes and Steel!
Or, just subscribe to the blog:
#ruby #middleman #coding #directsales #marketing #website #webdev #lemonsqueezy