# Batin Studio > Shopify CRO agency and Shopify Select Partner for Shopify brands doing $100k+ a month. We find what stops shoppers from buying, A/B test the fix on the store, and keep the winners as theme code the brand owns. We also build Shopify apps: Show Discount and Auto Media Optimizer. Key facts: - What we do: conversion rate optimization (CRO) for Shopify stores. Our work starts after the click, on the storefront, from landing page to thank-you page. - Goal metrics: conversion rate, average order value (AOV) and revenue per visitor. - Who it's for: Shopify and DTC brands doing $100k+ a month in revenue that already have traffic. The brand (or its ads team or agency) brings the traffic; we turn more of it into revenue, and work alongside whoever runs the ads. - Test commitment: 2+ tests live on the store every month. That's a floor; the real number depends on the store's traffic. - Testing tool: Intelligems (content, theme, price, offer and shipping tests). The client pays for its own tools; we set them up and run them. - One team, in-house: research, test design, design, development and testing. Winners are shipped as permanent theme code; when a fix needs an app feature, we can build it. - Pricing: one CRO plan. Monthly $1,999/month (cancel anytime) · Yearly $1,899/month, billed $22,788 upfront · Hourly $29/hour (5-hour minimum, then actual time). Every plan starts with a free call. - Free Shopify CRO audit: we review the store and its numbers and walk the brand through what we find, live on a call: where it loses sales, the first tests we'd run, and a straight answer on fit. No obligation (https://batinstudio.com/shopify-cro-audit). - Shopify Partner tier: Select (https://www.shopify.com/partners/directory/partner/batin-studio). - Founded 2021. A team of 3; founder Shakhawat Hossen. US-registered (Sheridan, Wyoming), team based in Bangladesh. - Contact: hello@batinstudio.com · Book a free call: https://batinstudio.com/book ## The CRO plan What's included every month: - 2+ tests live on your store every month - Know exactly where and why shoppers leave - A ranked list of what to fix first, offers included - Every variant designed and built for you - Your testing tool set up and run for you - Winners kept as permanent code you own - A plain monthly report: what won, and what’s next Three ways to pay: - Monthly: $1,999/month. Cancel anytime. No lock-in. - Yearly: $1,899/month. Billed $22,788 upfront. Save $1,200 a year. - Hourly: $29/hour. 5-hour minimum, then billed for actual time. Every plan starts with a free call (https://batinstudio.com/book): we check the store's traffic, numbers and goals before anyone pays. If testing won't pay off for the store yet, we say so. Clients pay for their own tools (Intelligems, analytics apps and, on the hourly plan, the time-tracking tool). ## How we work 1. Research: find where shoppers drop off and why, from the store's own data (funnel, device and traffic analytics, heatmaps, session replays, a speed and mobile check). You get: where your store loses sales, and why. 2. Hypothesis: every finding becomes a change, a target number and a rank in a shared backlog (pages, features, prices and offers). You get: a ranked plan of what to fix first. 3. Test: we design and code every variant, then split live traffic in Intelligems. 2+ tests live every month. You get: proof on your own customers, before you commit. 4. Ship: winners become permanent theme code; losing variants are switched off and removed. A plain monthly report: what won, and what's next. You get: every win kept, in code you own. ## What we test Six areas of the storefront, each with its goal: - Product pages: more orders. - Offers and bundles: bigger orders. We suggest offers to test (bundles, thresholds, gifts, pricing); when one wins, the brand's team runs it. - Cart: bigger orders. - Collections: more revenue per visitor. - Checkout and trust: fewer abandoned carts. - Speed and mobile: more revenue per visitor. ## FAQ ### Who is this for? Shopify brands doing $100k+ a month that already have traffic and want more of it to turn into revenue. Testing needs enough orders to give reliable answers, which is why we start there. ### Do you work with our ads team or agency? Yes. We handle the store side and work with whoever runs your ads. Every winning test makes the traffic they bring go further. ### How do you decide what to test? From your own data: analytics, heatmaps, session replays and your customers’ behaviour, the same research as our [free Shopify CRO audit](https://batinstudio.com/shopify-cro-audit). Each idea is ranked by expected impact and effort, and the backlog is shared with you. ### What happens when a test loses? It gets switched off and deleted, and the learning goes into the backlog. Nothing becomes permanent until it has been measured on your traffic. ### Which testing tool do you use? Intelligems. It covers content, theme, price, offer and shipping tests on Shopify. You pay for the subscription; we set it up and run it. More on how we run [Shopify A/B tests](https://batinstudio.com/shopify-ab-testing). ### Why does every plan start with a call? So we can check your traffic, numbers and goals before you pay anything. If testing won’t pay off for your store yet, we’ll tell you. ### Can I cancel the monthly plan? Yes. It’s month to month with no lock-in. Cancel anytime. ### How does the yearly plan work? The same plan at $1,899 a month, billed once upfront as $22,788. That saves $1,200 over twelve monthly payments. ### How does the hourly plan work? There’s a 5-hour minimum ($145). After that we bill for the actual time tracked. It’s a low-risk way to try us on a single fix, page section or test setup: [design](https://batinstudio.com/shopify-design), [development](https://batinstudio.com/shopify-development) or an [A/B test](https://batinstudio.com/shopify-ab-testing). ### Are tool costs included? No. You pay for your own tools, such as Intelligems, analytics apps and, on the hourly plan, the time-tracking tool. We help you choose and set them up. ### Do you run our ads or campaigns? We handle the store side and work with whoever runs your ads. We’ll suggest offers to test, and when one wins, your team runs it. ## Services ### Shopify A/B testing Shopify A/B tests, designed, built and run for you. Proof from your own shoppers before a change goes live for everyone. Page: https://batinstudio.com/shopify-ab-testing - Picked from your data: Each test starts from where your shoppers stall, ranked by impact and effort. - Designed and coded: We build every variant in your theme. No page-builder hacks. - Set up in Intelligems: Content, theme, price, offer and shipping tests, configured for you. - One goal per test: Conversion rate, order value or revenue per visitor, chosen up front. - Read with care: A test runs until it has enough visitors or orders for a reliable answer. - Winners shipped: The winner becomes permanent theme code. The loser is removed cleanly. **Can you A/B test on Shopify?** Yes. We use Intelligems, a Shopify testing app that splits your live traffic between versions of a page, a price, an offer or a shipping rule, and measures which one earns more. **How much traffic do I need?** Enough orders for a clear answer in a reasonable time. That’s why we work with stores doing $100k+ a month. On the call we look at your numbers and tell you honestly whether testing will pay off yet. **How long does a test run?** Until it has enough visitors or orders to give a reliable answer. How long that takes depends on your traffic and on what’s being tested, so we set the target before each test starts. **Can you test prices, offers and shipping?** Yes. Besides page and theme changes, Intelligems runs price, offer and shipping tests: a bundle against a free gift, or free shipping at $60 against $75, for example. **What happens when a test wins, or loses?** A winner is coded into your theme so every shopper gets it. A loser is switched off and removed, and what we learned goes back into the backlog. Nothing becomes permanent until it has been measured on your traffic. **Who pays for Intelligems?** You do, on your own account. We set it up and run it, and you keep the data if you ever stop working with us. **Can you set up a single test?** Yes, on the hourly plan: $29 an hour with a 5-hour minimum. The monthly plan keeps 2+ tests live every month. ### Shopify CRO audit A free Shopify CRO audit that ends in tests, not a PDF. Find where your store loses sales, and what to fix first. Page: https://batinstudio.com/shopify-cro-audit - Funnel and drop-off: Where shoppers leave, by device and traffic source. - Product pages: What stops a shopper from adding to cart. - Cart and checkout: Where carts are abandoned, and at which step. - Offers and pricing: Whether shoppers notice your offers, and which ones to test. - Speed and mobile: Slow pages, heavy images and apps that weigh down the theme. - Trust: Reviews, guarantees and returns: where they sit, and if they’re seen. **What is a Shopify CRO audit?** A review of your store and its data to find where shoppers drop off before buying, and why. Ours is free and ends in a ranked list of tests, so every finding turns into a change you can measure. **How is it different from a checklist audit?** A checklist compares your store with generic best practices. We start from your own analytics, heatmaps and session replays, so the fixes come from what your shoppers actually do. **What do I get at the end?** Where your store loses sales and why, a ranked list of what to fix first (offers included), and the first tests we’d run, each with the number it should move. **Is the audit really free?** Yes. We review your store and numbers and walk you through what we find, live on a call. No obligation either way. **What access do you need?** Collaborator access to your Shopify admin, your analytics, and a heatmap and session replay tool if you have one. If you don’t, we help you set one up. **Do I have to sign up after the audit?** No. What we show you is yours to keep. If you want us to run the tests, the plan is $1,999 a month and you can cancel anytime. **What if my store isn’t ready for testing?** We’ll tell you. Testing needs enough orders to give reliable answers; if your store isn’t there yet, we say so on the call. ### Shopify store design Redesign your Shopify store without betting on a relaunch. We redesign one part at a time, and keep each change only if it earns more. Page: https://batinstudio.com/shopify-design - Product pages: Photos, price, options and add to cart, laid out for buying. - Collections: Cards, filters and quick-add that get shoppers to the right product. - Cart and cart drawer: Upsells, shipping progress and a clear way to checkout. - Home and landing pages: Pages that match the ad or email that brought the shopper in. - Offers and bundles: How a discount, bundle or gift is shown, so shoppers notice it. - Mobile first: Designed for the phone first, where most shoppers browse. **Do you redesign whole stores?** We redesign the parts that cost you sales, one test at a time. If a new theme is the right call, we build it in stages, so each stage can be measured instead of relaunching everything on one day. **Why not redesign everything at once?** A full relaunch changes dozens of things together. If sales drop, or rise, you can’t tell which change did it. Testing one part at a time keeps what works and drops what doesn’t. **Will my team be able to edit the new pages?** Yes. We build Shopify sections and blocks, so your team edits text, images and products in the theme editor without touching code. **Do you work inside our brand guidelines?** Yes. We design inside your existing brand: your type, colours and photography, applied to pages built to sell. **Which themes do you work with?** Any Online Store 2.0 theme, on any Shopify plan. **What does it cost?** Design is part of the CRO plan ($1,999 a month, cancel anytime), with 2+ tests live every month. For a single page section, the hourly plan is $29 an hour with a 5-hour minimum. ### Shopify development Shopify development that earns its place in your theme. Theme code, app features and speed fixes, from the team that tests them. Page: https://batinstudio.com/shopify-development - Theme sections and blocks: Online Store 2.0 sections your team edits in the theme editor. - Product and cart features: Sticky add-to-cart, upsells, bundles and free-shipping progress. - Custom app features: When no app does what your store needs, we build it as a theme app extension. - Speed fixes: Lighter images, fewer scripts, and apps that stop slowing your pages. - Test variants: Every A/B variant, coded properly in your theme. - Clean-up: Leftover app code and old test variants, removed safely. **Do you take one-off development work?** Yes, on the hourly plan: $29 an hour with a 5-hour minimum, then billed for the actual time tracked. It suits a single fix, a page section or a test setup. **Can you build a custom Shopify app?** Yes, when no app does what your store needs. We’ve built and published two of our own, Show Discount and Auto Media Optimizer, so we know the App Store side as well as the theme side. **Do you work on Shopify Plus stores?** Yes. We work on any Shopify plan and any Online Store 2.0 theme. **Who owns the code?** You do. Everything we ship stays in your theme or your store, and keeps working if you stop working with us. **Will you edit our live theme?** No. We work on a copy of your theme, you review it, and it goes live once you approve it, often as an A/B test first. **Can you make my store faster?** Yes. Speed is part of our research: we find what slows your pages (heavy images, unused app scripts, theme bloat) and fix it, then check the effect on revenue per visitor. ## Shopify apps ### Show Discount: Dynamic Pricing Discount badges that sync live with your sales. One flat monthly fee. Never a cut of your revenue. - Page: https://batinstudio.com/products/show-discount - App Store: https://apps.shopify.com/showdiscount - Launched: June 2026 Features: - Automatic: Badges appear the instant a discount goes live and disappear when it ends. No manual updates. - Zero-code setup: Live in about 2 minutes on any Online Store 2.0 theme, through a theme app extension. - Flat fee: One price. Never a percentage of your sales. - Fully customisable: Match badge colours and text to your brand. - All discount types: Percentage, fixed amount, free shipping and Buy X Get Y. Plans: - Free: $0/month. Product page discount badges, Auto-sync with Shopify discounts, Full badge customisation. - Pro: $24.99/month (or $240/year (save 20%) · 7-day free trial). Everything in Free, Auto-apply discount codes, Cart drawer toast notifications, Collection page badges, Product card badges. ### Do I need to update the badges when a sale changes? No. Badges follow your Shopify discounts: create, change or end a discount and the badges update on their own. ### Does it edit my theme code? No. It runs as a theme app extension, so you turn it on and off in the theme editor and uninstalling leaves no code behind. ### Which discounts does it support? Percentage, fixed amount, free shipping and Buy X Get Y discounts created in Shopify. ### Do you take a share of my sales? Never. It’s a flat monthly fee, with a free plan for product page badges. ### Which themes does it work with? Any Online Store 2.0 theme. ### Auto Media Optimizer Every image on your store, compressed and web-ready in the background while you work. - Page: https://batinstudio.com/products/auto-media-optimizer - App Store: https://apps.shopify.com/auto-media-optimizer - Launched: December 2025 Features: - Compress on upload: Images are optimised automatically when they’re uploaded or updated. - Works in the background: No waiting and no clicks. Keep working while it runs. - No visible quality loss: Smart compression that keeps images looking sharp. - Store-wide: Optimises consecutively across your store, media library included. Plans: - Free Starter: $0/month. Up to 50 images a month, Automated media optimisation. - Pro: $9.99/month (or $99/year (save 17%)). Unlimited image optimisation, Automated media optimisation, Faster optimisation speed. ### Is there anything to do after installing? No. It starts right away and works in the background on every image you upload, update or replace. ### Do I need to change how I upload images? No. Upload, update or replace images as usual and the app optimises them in the background. ### Will my images lose quality? It uses smart compression designed to avoid visible quality loss. ### Does it cover images I already have? Yes. It works store-wide, media library included. ## Client reviews From design and development projects (not CRO results): > Batin Studio has been a huge help for TCB, and honestly, I couldn’t recommend them more. If you’re looking for web dev help, our experience has been nothing short of great. > > Mauricio Gotera, CMO, The Conscious Bar (Miami, Florida, USA) > Really great UI/UX design! Honestly, it’s hard to find someone who goes out of their way to think of creative solutions. They don’t just follow exactly what you suggest, they think critically about the problem. > > Yohan Dante, CEO, Inspace (New South Wales, Australia) ## Blog posts ### Cart Abandonment and Invisible Discounts: Is a Hidden Sale Costing You Conversions? URL: https://batinstudio.com/blog/cart-abandonment-and-invisible-discounts-is-a-hidden-sale-costing-you-conversions · Shakhawat Hossen · 2026-06-29 · Cart & checkout Roughly 7 out of every 10 shoppers who add something to a Shopify cart leave without buying it. That number has held steady at around 70% for over a decade, across studies, across platforms, across however many checkout redesigns the industry has thrown at it. It's noticeably worse on mobile than desktop, which matters given how much Shopify traffic now arrives on a phone, but the underlying pattern is the same regardless of device. It's one of the most reliable stats in ecommerce, and also one of the most misunderstood, because most of the advice built around it focuses on the same handful of well-known culprits: surprise shipping costs, a checkout that asks for too much, a forced account creation step. Those causes are real and worth fixing. But there's a quieter one that almost never makes the list, specifically because it's hard to measure: a shopper who never actually saw the discount that was already working in their favor. ## What we actually know about why people leave Worth grounding this in real numbers before going further, because not all abandonment is recoverable, and pretending otherwise leads to chasing the wrong fix. Baymard Institute's research, the most cited source in this space, finds that around 43% of shoppers who abandon say they simply weren't ready to buy on that visit, they were browsing, comparing, or saving something for later. That's a large chunk of the 70% that isn't really a conversion problem at all, it's just how people shop. Of the remaining, addressable share, the most common named reasons are extra costs appearing late in checkout (cited by around 48% of abandoners), being forced to create an account (around 25%), a checkout process that feels too long or complicated, and a lack of trust in how payment information is handled. Every one of those is a documented, well-studied fix, and there's no shortage of guides covering exactly how to address each one. One reason sits closer to the topic of this post than the others: roughly 17% of abandoners cite the total cost not being shown clearly upfront. That's not specifically about discounts, but it's the same underlying issue, a shopper not having clear, trustworthy pricing information early enough in the journey to make a confident decision. What's notable is that almost none of the standard lists include anything resembling "I didn't realize there was a discount" as a named category. That's not because it doesn't happen, it's because it's nearly impossible to measure directly. Nobody fills out an exit survey explaining that they left because a sale they qualified for never visually registered. It shows up in the data as ordinary, unexplained abandonment, indistinguishable from someone who simply changed their mind. ## Where invisible discounts fit into this Here's the connection worth making explicit. If your store has an active discount, an automatic one, a code shared in an email, a sale running on a specific collection, but nothing on the product or cart page visually reflects it, you've recreated a version of that same "unclear total cost" problem, just earlier in the funnel and self-inflicted rather than caused by a surprise shipping fee. Think about what's actually happening from the shopper's side. They land on a product page. The price looks like a normal, full price, because nothing distinguishes it as discounted. They add it to the cart anyway, maybe they still want it, maybe they're price-comparing against other tabs, maybe they're just not in a rush. And here's the part that matters: there's nothing on that page creating a reason to finish the purchase today rather than next week. A visible "was \$65, now \$40" does real psychological work that an identical but invisible discount doesn't. It anchors the shopper to the idea that they're already getting a deal, and walking away from the cart starts to feel like walking away from money already saved, which is a meaningfully different feeling than just walking away from a price they could find anywhere. That's loss aversion doing the job urgency is supposed to do, and it only fires if the discount is something they can actually see. Without that visible anchor, an active discount provides none of the urgency it's capable of providing. You're paying the same margin cost as a store that shows its sale clearly, while getting none of the conversion benefit that's the entire reason discounts work as a tactic in the first place. Picture a shopper with two tabs open, your product page and a competitor's, both showing roughly the same price for similar items. If your price is actually discounted right now but doesn't look it, and the competitor's isn't discounted but happens to look slightly cheaper at a glance, you lose that comparison for reasons that have nothing to do with what either store is actually charging. The discount you're already paying for in margin loses to a sale that was never real, purely because of which page made its price legible faster. ## The version with a code involved is worse, not better If you've read our piece on discount codes failing at checkout, you already know codes add their own layer of friction. There's a related version of that problem that shows up earlier, before checkout even starts. A shopper who received a code by email, found one on social media, or got it from an influencer, arrives at the product page with a specific expectation: this should be cheaper than what I'm looking at right now. If the page gives them no confirmation that anything has changed, no badge, no adjusted price, nothing, they're left holding an unresolved question instead of a clear answer. Does the code still work? Did I copy it wrong? Is this even the right product? That hesitation sits in roughly the same territory as the documented "lack of trust" and "checkout too complicated" abandonment causes, except it's happening a full step earlier, before they've even reached the part of the funnel most stores spend their optimization budget on. A shopper who isn't sure whether their discount applied is statistically more likely to leave and "deal with it later" than one who can see, immediately, that it already has. In practice "deal with it later" quietly becomes never, the tab closes, the email gets buried under twenty others, and the purchase that almost happened just doesn't. ## What this is plausibly costing you It's worth being honest about scale here rather than reaching for an alarming headline number. The frequently quoted "\$4 trillion lost to cart abandonment" figure gets thrown around a lot, and it's not a particularly useful one, since most of that total comes from the 43% who were never going to buy regardless of what your product page looked like. The more grounded estimate, the one Baymard itself prefers, is closer to \$260 billion in recoverable revenue across US and EU ecommerce, recoverable specifically through fixing the friction that's actually fixable. Invisible discounts sit squarely in that recoverable bucket, because the fix doesn't require touching your checkout flow, your shipping rates, or your account creation policy at all. It's purely a visibility problem on a page you already control. If even a modest share of your already-intent-driven abandoners, the 57% or so who weren't just browsing, are seeing a price that doesn't reflect savings that genuinely exist, that's lost conversion you're not even aware you're paying for, since nothing in your analytics specifically flags "discount was active but invisible" as a reason someone left. A useful way to size this for your own store: take your current conversion rate on pages where a discount is active, and compare it honestly to your conversion rate on a comparable non-discounted page. If a live sale isn't outperforming a regular price by a noticeable margin, that's a real signal worth investigating, a discount that doesn't move conversion any more than full price isn't failing as a tactic, it's failing to register at all. ## Making the discount impossible to miss The fix is less about a specific tool and more about a principle: if a discount is real, it should be visible everywhere a shopper is making a decision, the product page, the collection grid, and the cart, not just buried in the final total at checkout. Concretely, that means a badge or strikethrough price that shows up the moment a discount is active, not just a lower number with no context. It means a cart that visibly reflects the savings rather than a flat total that looks the same whether a discount applied or not. And if codes are part of your strategy, it means giving the shopper some signal that their code is recognized before they've committed to checking out at all, not after. This is the exact gap [Show Discount](https://apps.shopify.com/showdiscount) is built around, a badge that syncs automatically with whatever discount is actually live, so the visible price and the real price never drift apart. Whether you solve it with an app or with manual price field updates, the principle matters more than the method: an active discount nobody can see is functionally the same as no discount at all, except you're still paying the margin cost of one. ## A few quick answers **Is "just browsing" abandonment worth trying to fix?** Not really, and trying to chase it usually wastes effort better spent elsewhere. That segment wasn't going to buy on that visit regardless of price or visibility. The opportunity is in the shoppers who had real intent and hit friction, that's the addressable 57%. **How would I even know if invisible discounts are costing me conversions?** There's no analytics flag for it directly, since it shows up as ordinary cart abandonment with no distinguishing signal. The more useful question is simpler: open your own product pages right now while a discount is active and check honestly whether you, as a stranger, would know there's a deal happening. **Does this matter more for some kinds of discounts than others?** Automatic discounts are the highest-risk case, since there's no code, no email, nothing prompting the shopper to expect a lower price, the page is the only place it could possibly show up. Code-based discounts are slightly more forgiving since the shopper already has some expectation going in, but they still benefit from visible confirmation rather than silent faith that it'll work out at checkout. **Would fixing this actually move my overall abandonment rate, or is the effect too small to notice?** Probably not enough to single-handedly move your headline abandonment percentage, that number is dominated by the unavoidable browsing segment and broader checkout friction. The more honest way to think about it is as one specific, fixable leak rather than a fix for abandonment in general, worth closing on its own terms rather than expecting it to show up as a dramatic shift in a top-line metric. --- ### Free Shipping Bar vs Discount Badge: Which Promo Display Actually Converts Better? URL: https://batinstudio.com/blog/free-shipping-bar-vs-discount-badge-which-promo-display-actually-converts-better · Shakhawat Hossen · 2026-06-29 · Discounts & offers These two are probably the most common promotional elements on Shopify storefronts after the price itself. A discount badge sitting on a product image. A progress bar in the cart telling you you're \$12 away from free shipping. Both are backed by real psychology, both show up in roughly every theme marketplace screenshot, and both get fought over for the same precious real estate above the fold. Plenty of merchants end up picking one almost by accident, whichever app they installed first, without ever actually weighing what each one is doing differently. The honest answer to "which converts better" is more useful than picking a winner, because they're not actually competing for the same job. They work on different parts of the decision, at different moments, using different psychological levers entirely. Understanding that difference matters more than knowing which one wins an isolated A/B test, since the real question for most stores isn't which one to pick, it's which one to build first and why. ## What a discount badge is actually doing A badge or strikethrough price works through anchoring. The moment a shopper sees an original price next to a lower one, their brain has a reference point, and the new price gets evaluated against that reference rather than against some abstract idea of what the product "should" cost. \$40 read on its own is just a number. \$65 crossed out next to \$40 is a number with a story attached, and the story is "you're getting a deal," which is a much easier thing to act on than evaluating a price in a vacuum. This mechanism does its work early, on the product page, before a shopper has even decided to add anything to a cart. It's answering the question "is this worth buying," not "should I keep shopping" or "should I finish checking out." That's an important distinction, because it means a badge's job is mostly done once the item is in the cart. It got the shopper to commit. What happens after that is a different problem entirely. Picture two shoppers looking at the same \$40 candle. One sees just "\$40." The other sees "\$65, now \$40." Both are paying the identical amount. Only one of them feels like they just made a smart decision, and that feeling is doing real work toward whether they keep browsing or head to checkout right then. ## What a free shipping bar is actually doing A shipping progress bar works through a different pair of mechanisms: the goal gradient effect, the well-documented tendency for people to accelerate effort as a visible goal gets closer, and loss aversion, the fact that the prospect of missing out on something already in view feels worse than the equivalent gain felt good in the first place. "You're \$12 away from free shipping" isn't really about the \$12. It's about making a shopper feel like they're on the verge of losing something they can already see, which is a stronger pull than a flat statement like "free shipping on orders over \$75" sitting quietly near the cart total. This mechanism does its work later than a badge does, inside the cart, at exactly the moment a shopper is deciding whether to add one more thing or just check out. It's also directly aimed at the single most well-documented cause of cart abandonment across ecommerce: unexpected costs appearing late in checkout, cited by something like half of all abandoners in Baymard Institute's research, the same data we covered in our piece on cart abandonment and invisible discounts. A shipping bar attacks that specific problem before it becomes a surprise, by making the cost and the way around it visible the whole time a cart is being built. Same two shoppers, different moment. Both have \$58 in their cart. One sees nothing about shipping until the final total at checkout, where a \$9 fee appears with no warning. The other has been watching a bar all along that said "\$17 away from free shipping," shrinking with every item added. The first shopper experiences a surprise. The second experiences a near-miss they can still fix, and fixing a near-miss feels a lot more motivating than discovering a surprise fee ever does. ## Why the head-to-head framing is a bit of a trick question Put plainly: a badge is trying to get a shopper to decide a product is worth buying. A shipping bar is trying to get a shopper who's already decided that to either add more or stop hesitating at the final step. Those are different jobs, happening at different points in the same visit, and a store that only builds one of them is leaving a different kind of money on the table depending on which one it skipped. Skip the badge, and you're paying full margin cost for discounts nobody can see, the exact problem we've covered elsewhere in this series, real savings that do none of the conversion work they're capable of because nothing makes them visible. Skip the shipping bar, and you're letting the single biggest documented abandonment trigger sit there unaddressed, a shopper who built a cart, intended to buy, and walked away the moment an unexpected cost showed up at the worst possible time to discover it. Run an actual side-by-side test between the two and you'd likely find they're not even pulling from the same pool of would-be abandoners. A badge recovers shoppers who hadn't decided the product was worth it yet. A shipping bar recovers shoppers who'd already decided and were on the verge of walking away over cost framing instead. Comparing their conversion lift directly is a bit like comparing a better headline to a better closing line, both matter, neither replaces the other. ## If you can only build one first In practice almost every store ends up wanting both eventually, but if you're choosing where to start, a few questions point toward an answer faster than a generic "best practice" would. If your shipping rates are already a known sticking point, customers commenting on it, a noticeably high cart-to-checkout drop-off, start with the shipping bar. It's solving a documented, specific, and very common leak. If you run discounts or sales regularly and have any reason to suspect they're not visually registering, badges showing up inconsistently, automatic discounts with no visual confirmation anywhere, start there instead. A discount that isn't visible is doing zero percent of the job it's paying margin for, which is about as clear a fix as exists in conversion work. If you genuinely don't run sales often and your shipping is already free or genuinely flat-rate and well communicated, neither of these is your highest-leverage fix right now, and that's worth knowing too, building either one wouldn't move much if the underlying condition it's designed to fix doesn't really apply to your store. One more practical filter: think about where your traffic actually lands. A store driving most of its visits straight to specific product pages from ads or social leans more heavily on the badge doing its job early, since that's the first and sometimes only page a shopper sees before deciding. A store with a lot of repeat browsing and cart-building behavior, multiple items added across a session, leans more on the shipping bar, since there's more opportunity for the threshold mechanic to actually influence what gets added. ## Running both without them stepping on each other If you do end up building both, the failure mode worth avoiding is cramming everything into the same visual space. A badge belongs on the product image or right next to the price, doing its job at the decision point. A shipping bar belongs in the cart and cart drawer, doing its job at the commitment point. Stacking a badge, a shipping bar, a countdown timer, and a row of trust icons into one banner at the top of every page dilutes all of them into background noise a shopper learns to scroll past within their first few visits. Give each element its own clear moment and they'll keep doing the specific job they're each good at. ## A caution about the lift numbers floating around If you go looking for hard data on either of these, you'll find an enormous range, AOV lifts reported anywhere from high single digits to numbers that sound closer to a different business than yours. Most of that comes from vendor case studies and app marketing pages, which is a reasonable source of directional evidence, but not something to import as a guarantee for your own store. Your traffic, margins, average order value, and existing checkout friction all shift these numbers meaningfully in either direction. Treat any specific percentage you read, including the better-sourced ones, as a hint about which direction to expect movement, not a number to write into a forecast. A 12% lift quoted from a \$40 AOV apparel store and a 12% lift quoted from a \$300 AOV furniture store aren't actually describing comparable outcomes, even though the headline number looks identical. The one figure worth trusting more than the rest is the underlying cause itself: unexpected costs are consistently the most cited reason for cart abandonment across every major study in this space, that part holds up regardless of which app's blog you're reading it on. ## Where this leaves a discount-focused app like ours [Show Discount](https://apps.shopify.com/showdiscount) is built specifically for the badge half of this comparison, not the shipping side, worth saying plainly rather than stretching the pitch to cover both. If your honest answer to "is my active discount actually visible right now" is no, that's the half of this post worth acting on first. If your real leak is shipping cost surprise, that's a different fix entirely, and no badge app, ours included, is the right tool for that specific job. ## A few quick answers **Should every store have both eventually?** Most benefit from both, since they're solving genuinely different problems rather than competing solutions to the same one. The "which first" question matters more than "which instead of." **Does a free shipping bar work if I don't actually offer free shipping?** No, and don't fake one. The entire mechanism depends on the goal being real and reachable, a progress bar toward a threshold that doesn't exist or never triggers anything is a trust problem waiting to surface the first time a customer notices. **Which one should a brand-new store with almost no traffic data build first?** Lean toward the badge if you're running any kind of launch discount, since you have no abandonment data yet to confirm shipping is even a problem for your specific shoppers. The shipping bar becomes the clearer call once you've got enough cart-level data to see whether cost surprise is actually where people are dropping off. --- ### How to Set Up Buy X Get Y Promotions in Shopify (and Actually Get Shoppers to Notice) URL: https://batinstudio.com/blog/how-to-set-up-buy-x-get-y-promotions-in-shopify-and-actually-get-shoppers-to-notice · Shakhawat Hossen · 2026-06-29 · Discounts & offers Buy X Get Y is one of the better promotion types available on Shopify. It lifts average order value, it's a clean way to move slower-selling inventory alongside a bestseller, and shoppers generally like it more than a flat percentage off, getting something feels different from paying less for the same thing. It's also one of the easiest promotions to set up and have quietly do nothing at all, because of a native behavior most merchants don't find out about until they're wondering why a "successful" promotion produced zero extra orders. Imagine running "Buy 2 candles, get 1 free" for a full month. You check the discount's usage report and the number sits at zero, despite plenty of orders containing two or more candles during that window. The promotion wasn't broken. It was working exactly as configured, and exactly as configured turns out to mean something most merchants don't expect. We'll get to that part. First, the setup. ## Setting it up natively, step by step You don't need an app to create a basic Buy X Get Y promotion, it's a built-in discount type. 1. From your Shopify admin, go to **Discounts** and click **Create discount**, then choose **Buy X get Y**. 2. Give it a name. This shows up in your admin and on the customer's order, so make it something recognizable, "Buy 2 Get 1 Free, Socks" rather than "Promo4." 3. In the **Customer buys** section, set the trigger: either a minimum quantity or a minimum amount spent, and which products or collections qualify. Using a collection rather than individual products means new arrivals can qualify automatically later without you editing the discount again. 4. In the **Customer gets** section, set how many units the customer receives the discount on, and which products or collections those units come from. If you're running a true "buy this, get that" structure, this is usually a separate, specific product, if you're running "buy any 3, the cheapest is free," it can be the same collection used in the buy section. 5. In **At a discounted value**, choose Free, a percentage off, or a fixed amount off. 6. Choose whether it's an automatic discount or requires a code, then set the active dates, usage limits, and combination settings. 7. Save. A couple of things worth getting right while you're in there. If "Customer buys" and "Customer gets" point at the same collection, Shopify automatically treats the lowest-priced qualifying item as the free one, which is usually what you want, but worth double-checking if your collection has a wide price range. And if you're running more than one promotion at a time, check the Combinations settings on both, the same stacking rules that apply to percentage discounts apply here too. To make this concrete: for "Buy 2 candles, get 1 free," you'd set Customer buys to a quantity of 3 from your Candles collection, set Customer gets to a quantity of 1 from the same collection, and set the discounted value to Free. Shopify handles picking out which of the three is the free one automatically, you don't need to designate a specific item as long as they're all from the same eligible collection. ## A few structures worth knowing about "Buy X Get Y" covers more ground than the classic BOGO. A few variations worth knowing since they all use the same setup screen, just different values: **Cross-sell gift with purchase.** Buy product A, get a specific, unrelated product B free or discounted. Common for introducing a new product line to existing customers, or pairing a high-margin accessory with a hero product. **Tiered free item.** Buy any 3 from a collection, get the cheapest one free. Works well for clearing inventory across a whole category rather than promoting one specific SKU. **Partial discount instead of free.** The "get" item doesn't have to be free, a 50% off second item is technically the same discount type, just with a different value in the discounted-value step, and it's gentler on margin if a fully free item doesn't pencil out for your product. **Spend-based qualification.** Instead of a quantity, "Customer buys" can be set to a minimum dollar amount, useful when the qualifying purchase could reasonably be any mix of products rather than a specific count of one thing. All four use the exact same admin flow above, the only thing changing is what you put in the buys, gets, and discounted-value fields. ## The part that breaks everything if you don't know about it Here's the detail that catches almost everyone running their first Buy X Get Y promotion: Shopify's native discount engine never automatically adds the free or discounted item to the customer's cart. Not for automatic discounts, not for discount codes. The customer has to find the qualifying "get" product themselves and add it manually, the discount only ever reduces the price of something that's already sitting in the cart. Think through what that actually means for a shopper who has no idea this is how it works. They add three T-shirts to their cart, the ones your "Buy 2 Get 1 Free" promotion is supposed to cover. Nothing visibly happens. No free item appears, no banner congratulates them, no line item changes. As far as they can tell, nothing about their cart reflects any kind of deal at all, because nothing does yet, the system is just waiting for them to also go find the specific free item and add it themselves, something they were never told they needed to do. Most shoppers don't go looking for a step nobody told them existed. They check out with three full-priced T-shirts, or they get confused, assume the promotion is broken or fake, and abandon the cart out of mild suspicion. Either way, a promotion that looked successful in your admin, properly configured, active, no errors, produced exactly the same outcome as not running one at all. This is also why usage reports on a poorly surfaced Buy X Get Y promotion can look misleadingly bad. A low redemption count doesn't necessarily mean shoppers weren't interested in the deal, it often just means they never found out there was a second step required to get it. ## Why this hits Buy X Get Y harder than other discount types A percentage-off discount has one job: be visible. Once a shopper has the qualifying item in their cart, the deal is already structurally complete, it just needs to be seen. Buy X Get Y has two jobs stacked on top of each other. It needs to be visible, the same as any other discount, and on top of that, it requires an additional, specific action before it does anything at all, finding and adding a second product the shopper may not have even been shopping for. That's a meaningfully higher bar than just noticing a lower number on a price tag, and it's exactly why this promotion type quietly underperforms more often than simpler ones, even when it's configured perfectly. It's worth comparing this directly to how a percentage discount fails versus how Buy X Get Y fails. An invisible percentage discount still produces a sale, just at a lower margin than you'd like and without the urgency a visible deal creates. An invisible Buy X Get Y promotion produces nothing different at all, the shopper checks out exactly as they would have if the promotion didn't exist. The downside risk is structurally worse, because there's no partial credit for a deal nobody acted on. ## Two separate problems, two separate fixes It's worth treating these as genuinely different problems, because the fixes aren't the same. **Making the offer visible in the first place.** This is the more fundamental fix, and the cheapest one. A badge on the product page stating the actual terms, "Buy 2, Get 1 Free", a banner on the relevant collection page, a mention in the cart if a qualifying item is present but the free one isn't yet. None of this requires touching the discount logic itself, it's purely about making sure a shopper encounters the offer before they're deep enough into checkout that going back to add another item feels like a hassle rather than a discovery. Even something as simple as a sentence on the product description, spelled out in plain terms rather than assumed to be obvious, closes most of the gap for free. [Show Discount](https://apps.shopify.com/showdiscount) handles this specific piece, it displays a badge synced to your active discounts including Buy X Get Y, so the offer is visible on the product page itself rather than living only inside the Discounts admin where customers never see it. **Reducing the friction of actually adding the free item.** This is a separate, narrower problem; even a shopper who knows the deal exists still has to take an extra action to claim it. They have to remember which product qualifies, navigate to it, and add it, three steps for something that should arguably be one. A small category of apps exists specifically to auto-add the qualifying item to the cart once conditions are met, removing that step entirely, often by detecting the buy condition and prompting the shopper with a one-click add rather than a full product page visit. Worth knowing this category exists if the extra click is genuinely costing you conversions, though for most stores, simply making the offer visible and easy to understand solves the bulk of the problem without that added layer. ## A few quick answers **Does the discount apply automatically, or does the customer need a code?** Your choice during setup. Automatic discounts apply the moment the cart conditions are met, no code needed. Code-based ones require the customer to enter it at checkout, same as any other discount type. **What happens if a customer adds the "buy" item but never adds the "get" item?** Nothing, in either direction. They're not charged incorrectly and nothing breaks, they simply check out at full price, having never claimed a discount that, from Shopify's perspective, was always available to them. **Can I run Buy X Get Y in my physical store too?** Depends on your POS plan. It works at both online and in-person checkout on POS Pro. On POS Lite, Buy X Get Y discounts are limited to your online store and won't apply at in-person checkout. **Does this work on the post-purchase upsell page?** No. Buy X Get Y discounts created in the Shopify admin don't apply to post-purchase offer pages, that's a separate system with its own discount handling. **Can I limit the promotion to new customers only, or specific customer segments?** Yes, Buy X Get Y discounts support the same eligibility settings as other discount types, you can restrict it to specific customer segments, tags, or leave it open to everyone, all from the same discount setup screen. --- ### Shopify Theme App Extensions Explained: Why "No Theme Code" Apps Are Safer for Your Store URL: https://batinstudio.com/blog/shopify-theme-app-extensions-explained-why-no-theme-code-apps-are-safer-for-your-store · Shakhawat Hossen · 2026-06-29 · Apps You've probably seen the phrase somewhere on an app's listing page: "no theme code required," or "built on Online Store 2.0," or some version of "uninstalls cleanly, nothing left behind." It reads like marketing copy, and sometimes it is, but underneath it there's a real, specific piece of Shopify's architecture doing the work, called a theme app extension. Understanding what it actually does is worth a few minutes, because the difference between an app that uses one and an app that doesn't shows up exactly when you'd least want a surprise: when you're uninstalling something, switching themes, or wondering why your storefront suddenly looks broken after an update that had nothing to do with the app in question. If you've ever uninstalled an app months ago and still occasionally see a strange gap, a broken script error in your browser console, or a section that won't fully delete, there's a decent chance you're looking at exactly the problem this system was built to prevent. ## How apps used to integrate with themes Before 2021, an app that wanted to show something on your storefront, a badge, a review widget, a popup, generally had two options, and both involved touching your theme directly. The first was asking you, the merchant, to manually copy a Liquid snippet and paste it into a specific theme file, often theme.liquid, the global layout file that every page on your store runs through. The second was the app injecting JavaScript into your store using something called the ScriptTag API, which let an app's code run on every page without you doing the copy-pasting yourself, but still meant foreign code was now living inside your storefront indefinitely. Both approaches worked, plenty of stores ran on exactly this setup for years. But they shared the same structural problem: the app's code became physically mixed into your theme. Update your theme, and a snippet sitting in the old version doesn't carry over cleanly. Switch themes entirely, and you're often re-doing that copy-paste step from scratch. Uninstall the app without removing the snippet yourself first, and the code just stays there, sometimes harmlessly idle, sometimes throwing errors on a page that references a script that no longer has anything to talk to. A concrete version of this: a merchant installs a review app two years ago, pastes the required snippet into product.liquid as instructed, and it works fine. They switch themes last year for a redesign, the snippet doesn't carry over because nobody told the new theme it needed to be there, and the merchant never notices because reviews simply stopped showing, no error, no warning, just a feature that quietly disappeared. They uninstall the app this year, having long forgotten the snippet exists, and it sits there indefinitely, doing nothing, referencing a service that no longer exists. ## What a theme app extension actually is Shopify introduced theme app extensions in 2021 alongside Online Store 2.0, specifically to get app code out of merchant theme files entirely. The core idea: instead of writing into your theme, an app builds a separate, self-contained extension package, using Shopify's own CLI tooling, and that package gets exposed to your theme editor as something you can add, remove, and reposition yourself, without ever opening a code editor. There are two flavors of this. **App blocks** are positioned, visible elements that live inside a specific theme section, a badge inside the product information section, a size chart on a specific template. You add them, move them, and remove them the same way you'd rearrange any other section in the theme customizer, and the app developer has no ability to silently decide where they show up, that's entirely in your hands. **App embed blocks** are the other type, used for things that don't need specific placement, a chat bubble, a tracking script, a floating badge. These get toggled on or off as a whole from a dedicated "App embeds" panel in your theme settings, off by default until you turn them on. The meaningful difference from the old approach isn't really about how it looks to you, it's about where the code actually lives. With a theme app extension, your theme's files never get touched. The app's logic stays in the app's own versioned package, built and deployed through Shopify's CLI and hosted on Shopify's CDN, and Shopify's theme editor is just rendering a reference to it, the same way it renders any other built-in section. A developer can push an update to that package, and every store using the app gets the change automatically, without you reinstalling anything or pasting in a single updated line. ## Why this matters even if you never plan to touch code It's tempting to file this under "developer stuff" and move on, but the practical consequence lands squarely on merchants, not developers. You're the one who deals with a broken page months after an uninstall nobody warned you would leave anything behind. You're the one re-pasting snippets every time you redesign with a new theme. The architecture is technical, the pain it either causes or prevents is entirely yours to live with, which is exactly why it's worth understanding even if you'll never personally write a line of Liquid. ## The concrete safety difference This isn't just a tidier architecture for its own sake, it changes what happens at the two moments that matter most: updating your theme, and uninstalling the app. Shopify's own documentation states it plainly: when a merchant uninstalls an app, any blocks associated with it are automatically and entirely removed from the theme. Not "should be," not "in most cases," removed, fully, as part of the uninstall itself. That's the direct fix for the classic old-style problem of a snippet sitting orphaned in theme.liquid months after you forgot you'd ever pasted it there in the first place, the kind of leftover code that occasionally surfaces as a mysterious console error long after anyone remembers installing the app that caused it. The theme update side benefits too. Because the app's code never lived inside your theme's files to begin with, updating your theme to a new version, or switching to a completely different theme, doesn't require re-doing any installation step for the app. As long as the new theme supports app blocks, your existing app content carries over without you touching anything. There's a third benefit that matters more as you install more apps: conflicts. Old-style code injection from several apps at once, all editing or appending to the same theme.liquid file, is a well-known source of subtle bugs, one app's script interfering with another's, load order issues, duplicated functions. Because each theme app extension is sandboxed to its own blocks and embeds rather than freely editing shared files, that specific category of multi-app conflict mostly stops being possible in the first place. ## What this doesn't automatically guarantee A few honest caveats worth knowing, since "uses a theme app extension" isn't a blanket promise that solves every possible concern. App blocks specifically only work on Online Store 2.0 themes, the ones built with the newer JSON template structure. Older "vintage" themes can't support app blocks at all, full stop. App embed blocks are more forgiving, they work on both vintage and Online Store 2.0 themes, which is part of why apps that don't need precise positioning often lean on that format specifically to support the widest range of stores. It's also worth knowing that not every app on the Shopify App Store actually uses this system, even today. Shopify's own help documentation still lists "adding custom code directly to your theme" as a legitimate, currently available way apps integrate, alongside app blocks and embeds. Some apps choose that path deliberately, sometimes for genuinely good technical reasons that a block or embed can't accommodate. The point isn't that direct code injection is automatically bad, it's that "theme app extension" and "old-style code injection" are both still in active use, and they're not the same thing, so it's worth knowing which one you're actually getting. ## How to actually check before you install A few quick ways to confirm what you're dealing with, rather than taking a listing's word for it. Check the app's description for an explicit mention of Online Store 2.0 or theme app extensions, Shopify specifically recommends developers disclose this, so its absence is itself a small signal worth noticing. After installing, open your theme editor and look in two places: the block picker within a relevant section, for an "Apps" entry showing the app's block, and the dedicated "App embeds" panel in theme settings, for anything that toggles on there. If neither shows up anywhere, the app is likely using the older direct-code approach instead. If you want real certainty, test it on a duplicate of your theme: install the app, confirm it works, then uninstall it and check whether anything's left behind in your theme's code editor. A clean uninstall with nothing remaining is the clearest possible confirmation. This is the system [Show Discount](https://apps.shopify.com/showdiscount) is built on, badges render through a theme app extension rather than anything written into your theme files, which is also why setup takes about two minutes and uninstalling leaves nothing behind to clean up later. ## A few quick answers **Does this mean my theme can never break because of an app again?** It removes the most common failure mode, leftover or conflicting code, but it's not an absolute guarantee against every possible issue. A poorly built app block can still misbehave visually or load slowly, it just won't leave permanent debris in your theme files the way old-style injection could. **How do I know if my theme even supports this?** Any theme built on Online Store 2.0 supports app blocks, which by now is the large majority of actively maintained Shopify themes, including every default theme Shopify currently ships. If you're on a theme that hasn't been updated in several years, it's worth checking specifically, since older vintage themes don't support app blocks regardless of how the app itself is built. **Is custom code injection always worse than a theme app extension?** Not inherently, some legitimate integrations still need it. The difference is accountability: with a theme app extension, removal is guaranteed and automatic. With direct code injection, cleanup depends on the app, and you, remembering to do it. **If an app uses app embeds instead of app blocks, does that mean it's a worse or older integration?** Not at all, it usually just means the app's feature doesn't need specific positioning on the page. A chat widget or a tracking script genuinely belongs as a site-wide toggle rather than something dragged into a particular section, app embeds are the correct, modern choice for that category of feature, not a downgrade from app blocks. --- ### The Hidden Cost of "Free" Shopify Apps: What Revenue-Share Pricing Means for Your Margins URL: https://batinstudio.com/blog/the-hidden-cost-of-free-shopify-apps-what-revenue-share-pricing-means-for-your-margins · Shakhawat Hossen · 2026-06-29 · Apps Every Shopify merchant has installed an app because the pricing page said "Free." It's a reasonable thing to be drawn to, you're already paying for Shopify itself, plus a theme, plus a dozen smaller tools, and "\$0/month" reads as one less thing to worry about. The catch is that "free" and "no cost" aren't always the same sentence. A growing number of apps in the discounts, upsells, and promotions space don't charge a flat monthly fee at all, instead, they take a percentage of the sales that pass through whatever feature they power. No subscription, no invoice, just a cut. It sounds friendlier than a bill. Whether it actually is depends almost entirely on numbers most merchants never run before installing. ## What revenue-share pricing actually means To be fair to apps that work this way, it's worth being precise about what's usually being measured. Most revenue-share apps don't take a cut of your entire store's revenue, that would be a wildly aggressive model and a hard sell even to merchants who don't run the math. What they actually take a percentage of is attributed sales, specifically the orders that went through their feature. A discount badge app might take a cut of orders where its badge or auto-applied code was used. An upsell app might take a cut of the upsell line items it added to the cart. The scope is narrower than "your whole business," but it's still tied directly to your revenue rather than to a flat cost you can predict in advance. That distinction matters, and it's also exactly why the pricing can feel reasonable at first and expensive later. A small store sees a small number. A growing store sees the same percentage applied to a much bigger number, and the bill grows with it, even though the app itself isn't doing meaningfully more work to earn that larger number. Picture a store doing \$3,000 a month through a discount feature when they installed a "free" app charging 2% of attributed sales. That's \$60 a month, genuinely cheaper than most flat-fee alternatives, and a completely reasonable decision at the time. Eighteen months later, after a good growth run, that same feature is touching \$40,000 a month in sales during active promotions. The percentage didn't change. The bill did, to \$800 a month, for the exact same feature doing the exact same job it did on day one. Nobody decided to start paying \$800 a month for a discount badge, the pricing model just arrived there on its own while nobody was checking. ## The math that doesn't show up on the pricing page Let's run actual numbers, using a fairly typical rate in this category, 2% of attributed sales, against a flat fee of \$24.99 a month, the kind of price you'd see from a straightforward flat-rate alternative. | Monthly sales through the feature | 2% revenue share | Flat \$24.99 fee | |-----------------------------------|------------------|------------------| | \$500 | \$10.00 | \$24.99 | | \$1,250 | \$25.00 | \$24.99 | | \$5,000 | \$100.00 | \$24.99 | | \$20,000 | \$400.00 | \$24.99 | | \$50,000 | \$1,000.00 | \$24.99 | The crossover point here lands at around \$1,250 a month in attributed sales, past that, the percentage costs more than the flat fee, and the gap only widens from there. For a store running an active discount or promotion, \$1,250 in a month isn't an ambitious target, it's often a single good week, sometimes a single good day during a sale. That last part is the real sting. A revenue-share fee scales with success specifically during the moments your store is succeeding the most, which for a promotions or discount app usually means your biggest sale events. Black Friday, a major seasonal markdown, a viral product moment, these are exactly the times your attributed sales spike, and exactly the times your bill spikes right alongside it. The tool is supposed to be helping you capture more revenue during your busiest period. Instead, that's the moment it gets the most expensive to use. ## The costs that aren't the percentage itself The math above is the headline issue, but a few other things compound it that rarely get mentioned on a pricing page. **Misaligned incentives.** A flat-fee tool earns its subscription whether you run one promotion a year or fifty. A revenue-share tool earns more the more discounting happens through it. That's not necessarily a sinister design, but it does mean the app's financial interest and your margin's interest aren't pointed in the same direction. You want just enough discounting to move inventory and acquire customers. The pricing model, structurally, prefers more. It shows up in small ways, a default setting nudged toward broader eligibility, a recommended discount depth that's a little steeper than what you'd have chosen on your own, a nudge to "boost results" by widening which products qualify. None of that has to be deliberate to still tilt slightly against your margin over time. **Budgeting you can't actually budget.** A flat fee is a line item. You know it in January, you know it in December, you can put it in a spreadsheet and forget about it. A percentage fee is a variable cost that moves with revenue you haven't earned yet, which makes it behave more like a payment processing fee than a software subscription. If you're trying to model gross margin with any precision, an unpredictable line item that's largest exactly when revenue is largest is a genuinely annoying thing to forecast around. **It quietly changes what kind of cost this is.** Software subscriptions are usually treated as a fixed operating cost, the same number whether this month was great or terrible. A revenue-share fee behaves like a variable cost of goods sold instead, eating into margin on every order it touches. Most merchants don't reclassify it that way mentally, they keep thinking of it as "the app I pay for," when it's functionally closer to a small, permanent discount on every sale it's attached to. ## When revenue-share pricing actually makes sense It's not a universally bad model, and it would be unfair to frame it that way. A few situations where it genuinely fits: A brand new store with uncertain volume and a tight budget benefits from paying nothing until something actually sells, that's real risk transferred away from a business that can't yet afford to gamble on a flat fee for a feature that might not even get used. Services that take on real risk alongside the percentage are a different category entirely. Buy-now-pay-later providers, for example, charge a transaction fee partly because they're carrying default risk on the customer's behalf, not just displaying something on a page. The percentage there is compensating for actual exposure, not just access to a feature. And for some merchants, the simplicity is worth it even past the breakeven point. If you genuinely don't want to think about pricing tiers and you're comfortable with a variable cost as long as it only shows up when you're making money, that's a legitimate preference, just one worth choosing knowingly rather than defaulting into. ## Finding your own breakeven point You don't need to take anyone's word for whether a specific app is worth it, the math is simple enough to run yourself in a few minutes. 1. Find the app's percentage rate and what it's actually calculated against, total store revenue or just attributed sales through its specific feature. 2. Pull your average monthly sales through that feature, or your best estimate if you haven't installed it yet. 3. Multiply that number by the rate. That's your expected monthly cost under revenue share. 4. Compare it to the flat-fee alternative, if one exists in the same category. 5. If your attributed sales are likely to grow, and for most stores trying to grow, that's the goal, run the same comparison again at double and triple your current volume, not just where you are today. That last step is the one most people skip, and it's the one that actually matters, since the whole point of a growing store is that today's numbers aren't the ones you'll be living with in a year. As a worked example: a 1.5% rate against \$8,000 a month in attributed sales comes out to \$120. If a flat-fee competitor in the same category charges \$30, you're already paying four times more for what is, functionally, the same feature. Run that same 1.5% against a more ambitious but entirely realistic \$25,000 a month a year from now, and it's \$375, twelve times the flat fee, for an app that hasn't changed at all in what it does. ## Where this leaves the pricing decision None of this means revenue-share apps are a trap, plenty are run honestly and priced fairly for what they do. It just means "free" on a pricing page is a starting point for a calculation, not the end of one. A flat fee that looks like a bigger number on day one is frequently the cheaper option by month six, and it's the only one of the two you can actually plan around in a spreadsheet without a revenue forecast attached. It's the principle I built [Show Discount](https://apps.shopify.com/showdiscount) around for exactly this category: a flat monthly fee, never a cut of what you sell, so the bill on your best month looks identical to the bill on your slowest one. ## A few quick answers **Is a percentage-based app always more expensive than a flat fee?** Not always, below the breakeven volume it's genuinely cheaper. The risk is assuming that stays true as your store grows, when the math works against you well before most merchants expect. **How do I find out if an app charges this way before installing it?** Check the pricing tab on its App Store listing closely, revenue-share plans are required to disclose the percentage and what it's calculated against, it's just often in smaller text than the flashy "Free" headline above it. **What if the app takes credit for sales it didn't really influence?** Worth checking the attribution model specifically. Some apps count any order from a customer who ever saw their widget, not just orders that clearly used the specific feature. That's a separate, valid concern from the pricing structure itself, and worth raising directly with support if the numbers ever look off. **Should I switch away from a revenue-share app I'm already using?** Run the breakeven math first before assuming the answer is yes. If your attributed sales are still comfortably under the crossover point, switching might cost you more in setup time than it saves. The math is worth checking on a recurring basis though, quarterly is reasonable, since the crossover point has a way of arriving quietly during a growth stretch nobody was specifically watching for. --- ### Adsgun Alternative: A Flat-Fee Way to Show Discount Badges on Shopify URL: https://batinstudio.com/blog/adsgun-alternative-a-flat-fee-way-to-show-discount-badges-on-shopify · Shakhawat Hossen · 2026-06-28 · Apps Shoppers rarely do mental math. If a discount exists somewhere in your store but doesn't show up on the product page, most visitors never realize it's there, and a chunk of them leave without buying. That's the gap discount badge apps exist to close, and it's why Adsgun has become one of the more popular options in this space. But popularity comes with trade-offs. A few merchants have noted in their Adsgun reviews that certain pricing tiers take a cut of sales rather than charging a flat rate, which understandably doesn't sit well with everyone. If you want the same core benefit, live, auto-synced discount badges, without a revenue share, here's what to know about the alternative. ## What Adsgun does well To be fair, Adsgun is a capable app. It displays strike-through pricing across product pages, collections, cart, and checkout, supports discount stacking, syncs with Shopify Markets for multi-currency stores, and connects to Google Merchant Center so promotions can show up in Google Shopping results. For stores that need that full breadth, especially multi-currency or loyalty-tier pricing, it's a reasonable choice. ## The pricing catch Where some merchants push back is the billing model. Certain Adsgun plans tie cost to a percentage of the sales the app helps generate, on top of or instead of a flat subscription. For a high-volume store, that can add up fast, and it's a structurally different kind of expense than a normal app subscription. If you're budgeting a fixed monthly software cost, a revenue-share fee is hard to plan around. ## How Show Discount is different Show Discount focuses on the most common use case, the product page badge, and prices it as a flat monthly fee with no revenue share, ever. The free plan covers unlimited product page badges, auto-synced live with your active Shopify discounts (percentage off, fixed amount, free shipping, and Buy X Get Y). The Pro plan, at \$24.99 a month, adds auto-applied discount codes, a cart drawer toast notification, collection page badges, and product card badges. Setup takes about two minutes through Shopify's official Theme App Extension system. No theme code editing required. ## Side by side | | Show Discount | Adsgun | |----|----|----| | Pricing model | Flat monthly fee | Flat fee plus revenue share on some plans | | Product page badges | Yes, free plan | Yes | | Collection page badges | Yes, Pro plan | Yes | | Cart display | Toast notification, Pro plan | Full itemized display | | Checkout display | Not yet | Yes | | Multi-currency (Markets) | Not yet | Yes | | Google Merchant Center sync | Not yet | Yes | | Setup | Theme App Extension, about 2 minutes | Theme App Extension | ## Which one fits your store If you run a multi-currency store, lean on loyalty-tier pricing, or want checkout-level discount messaging, Adsgun's broader feature set may be worth the cost structure. If your main goal is getting discounts to show clearly on product and collection pages without worrying about what a big sale month does to your software bill, Show Discount is built for exactly that, and the free plan lets you try it before deciding. ## Frequently asked questions **Does Show Discount take a percentage of my sales?** No. Both the free and Pro plans are flat fees. Your bill doesn't change based on how much you sell. **Can I switch from Adsgun to Show Discount?** Yes. Uninstalling Adsgun and installing Show Discount takes a few minutes, and your existing Shopify discounts sync automatically once it's set up. **Does Show Discount work on Online Store 2.0 themes only?** Yes, it uses Shopify's Theme App Extension system, which requires Online Store 2.0. Most themes published in the last few years qualify. ## Try it free Show Discount installs in about two minutes, and the free plan has no time limit. [Install Show Discount from the Shopify App Store →](https://apps.shopify.com/showdiscount) --- ### Best Shopify Apps for Displaying Discounts in 2026 (Free and Paid) URL: https://batinstudio.com/blog/best-shopify-apps-for-displaying-discounts-in-2026-free-and-paid · Shakhawat Hossen · 2026-06-28 · Apps If you've read our piece on why discounts don't automatically show up on the product page, you already know the core issue: Shopify's discount engine and its product display are two separate systems that don't talk to each other unless something is built to connect them. That something is usually an app. It's worth saying plainly that you don't strictly need one of these. You can set the compare-at price field manually on every product yourself, for free, forever. People do exactly that for small catalogs and the occasional sale. The apps below earn their keep the moment you're running more than a couple of promotions a year, selling more than a handful of products, or just don't want to remember to flip a field back the moment a sale ends. The tricky part is that "discount apps" on the Shopify App Store cover a huge range of jobs, bundles, BOGO logic, volume pricing, loyalty tiers, and only a slice of them are actually about the specific problem of making an existing discount visible, as a badge, a strikethrough price, or a sale label, without you manually touching every product. This list sticks to that slice. Five apps, free and paid, each genuinely good at a different version of the same job. One disclosure up front: I run Show Discount, which is on this list. I've tried to write its entry the same way as the others, here's what it does well and where it doesn't fit, and you can weigh that however you'd like. ## What actually matters when you're comparing these Before the list, four questions worth asking about any app in this category: **Where does it actually display?** Just the product page, or also collections, cart, and checkout? More coverage is more setup and usually more cost, and not every store needs all of it. **Does it sync automatically, or do you maintain it?** Some apps watch your native Shopify discounts and update on their own. Others want you to build the sale inside the app itself, which works, but means your discount logic now lives in two places instead of one. **Free plan, or paid only?** Several genuinely good apps in this space don't offer a usable free tier at all, which is fine if you know that going in, less fine if you find out after building a workflow around it. **What happens when the sale ends?** This is the one people forget to check. An app that doesn't clean up after itself can leave a "sale" price sitting on products indefinitely, or worse, leave price changes stuck even after you've uninstalled it. **Does it touch your theme code?** Some apps render through Shopify's Theme App Extension system, which means uninstalling is clean and there's nothing left behind. Others ask you to add or edit Liquid code directly, which works fine but is a small commitment you should walk into knowingly, not discover later when you switch themes. With that, here's the list. ## 1. Adsgun: Show Discounted Prices Adsgun goes the deepest of anything here. It auto-applies promotions and shows strikethrough Was/Now pricing on product pages, collection pages, the cart, and checkout, and it works with Shopify Markets if you sell in multiple currencies. It also supports a few promotion types most apps don't bother with: private promotions sent via a unique link, tag-based eligibility through customer accounts, and UTM-targeted promotions for tracking specific campaigns. It's a small, founder-run app rather than a massive incumbent, currently sitting around a 4.7-star rating, and the reviews consistently single out fast, hands-on support from the team. There's a genuinely free plan for your first promotion. Worth knowing before you commit to a paid tier: a couple of reviewers have pushed back on a paid plan that ties cost to a percentage of sales, so check the specific plan details if a predictable flat bill matters to you. **Best for:** stores that want discount visibility everywhere, including checkout, and don't mind a smaller, support-heavy app over a household name. ## 2. Bold Discounts Bold has been running storewide sales since 2012, and it takes a different technical approach than most of the rest of this list: instead of calculating a discount at checkout, it actually edits the product's price and compare-at-price fields directly. That sounds like a small distinction, but it means the sale shows up everywhere your price field is used, your online store, Shopify POS, even feeds like Facebook and Google, with no extra setup. You get scheduling, automatic start and end times, live countdown timers, and auto-tagging into dynamic "Sale" or "Clearance" collections. With 1,200-plus reviews and a 4.5-star rating, it's the most established name on this list by a wide margin. The tradeoff is that there's no real free plan for a live store, paid plans start at \$19.99 a month, and because it's editing your actual price data rather than calculating on the fly, it's worth paying attention to how cleanly it rolls prices back after a big sale, a small number of merchants have reported prices getting stuck after large events. It also integrates with other Bold apps, like Bold Upsell for BOGO offers, if you're already inside that ecosystem or planning to be. **Best for:** stores running frequent storewide sales that need the discount to show consistently across every sales channel, not just the online store. ## 3. DECO Product Labels & Badges DECO isn't a discount app first, it's a general product badge and label app that happens to do discounts very well. It automatically calculates and displays the percentage off on sale items, alongside a large library of other badge types: low stock, new arrival, BOGO, bestseller, and fully custom designs for things like Black Friday or seasonal sales. It's one of the most reviewed apps in its category, sitting around a 5-star rating across more than 1,400 reviews, and it carries Shopify's Built for Shopify badge. There's a usable free plan, with paid tiers unlocking more automation and customization, including an AI badge generator and scheduling so labels turn on and off on their own. The flip side of being this broad is that discounts are one feature among many, not the entire product. If all you need is a discount badge, DECO can do it, but you'll be configuring it inside a much bigger toolset built for general merchandising. **Best for:** stores that want one app to handle discount badges and a wide range of other promotional and merchandising labels at the same time. ## 4. Lably: Product Labels & Badges Lably covers similar ground to DECO at a lighter weight: product labels, badges, and stickers, including discount-driven ones, with a simpler interface and a smaller feature set to learn. It also carries the Built for Shopify badge and holds a 5-star rating across north of 600 reviews, with a free plan available. If DECO is the full toolkit, Lably is the pared-down version aimed at stores that want clean badges without a long settings menu to work through first. It still covers the basics that matter for discount display: percentage-off labels, sale stickers, and conditional display based on whether a product is actually marked down, just without the extra layers of scheduling and AI generation that come with DECO's bigger feature set. **Best for:** smaller catalogs that want straightforward discount and promotional badges without a steep setup process. ## 5. Show Discount This is the one I built, so take the framing with that in mind. Show Discount focuses on a single job: a live badge next to the product price that's auto-synced with your actual Shopify discounts, percentage off, fixed amount, free shipping, and Buy X Get Y. It appears the moment a discount goes live and disappears the moment it ends, with no separate sale to configure and nothing to manually revert afterward. The free plan covers unlimited product page badges. The Pro plan, at a flat \$24.99 a month, no percentage of sales, ever, adds auto-applied discount codes at checkout, a cart drawer toast notification, collection page badges, and product card badges. Setup runs through Shopify's Theme App Extension system and takes about two minutes, no theme code editing. It doesn't reach checkout-level display the way Adsgun does, and it's not a general merchandising badge tool the way DECO or Lably are. It's deliberately narrower than both, built after one too many cases of installing a heavier discount app on a client store for what was, every time, the same simple request: just show that the price dropped. **Best for:** stores that want the core "discount is live, so show it" loop solved simply, with predictable flat pricing and minimal setup, without taking on a bigger feature set they won't use. ## A few quick answers **Can I run more than one of these at the same time?** Technically, but it's not a great idea. Two apps trying to render a badge or manage the compare-at price on the same product tend to conflict with each other, and you'll spend more time untangling which app is responsible for what than you'll gain from the overlap. Pick one for this job. **Do any of these replace Shopify's native Discounts section?** Mostly no. You're still creating the actual discount rule, percentage off, fixed amount, BOGO, in Shopify's own Discounts admin in most cases. These apps read that rule and handle showing it, or in Bold's case, apply it directly to the price field. The exception worth knowing is that a couple of apps in this broader category create their own discount logic independent of Shopify's native rules, which is a different model with its own tradeoffs. ## How to actually choose A reasonable way to narrow this down fast: think about which pages actually need to show the discount, not which app has the longest feature list. A product page badge solves the problem for most stores. Checkout-level display matters more if you're running paid traffic straight to product pages and want zero surprises by the time someone reaches the total. Storewide price changes that need to show up on POS or social feeds are a different requirement entirely, and only one app on this list is built around that specifically. | If you want... | Look at | |-------------------------------------------------------|----------------| | Discount visibility at checkout and across currencies | Adsgun | | One sale price that shows everywhere, including POS | Bold Discounts | | A big library of badges beyond just discounts | DECO | | The same idea as DECO, with less to configure | Lably | | Just a simple, auto-synced product page badge | Show Discount | There's no single best answer here, the right pick depends on how much of your storefront you need to cover and how much complexity you're willing to take on to get there. If you're not sure yet, starting with a free plan and seeing how far it gets you before reaching for something heavier is a perfectly reasonable way to decide, and four of the five apps above give you a real way to do exactly that. Whichever you land on, install it on a duplicate of your theme first if you can, especially anything that edits Liquid code or product price fields directly, and run one full test sale before pointing real traffic at it. That five minutes of testing is cheaper than finding out what "stuck" looks like during your biggest sale of the year. --- ### How to Show a Crossed-Out Original Price Next to Your Sale Price on Shopify (No Code) URL: https://batinstudio.com/blog/how-to-show-a-crossed-out-original-price-next-to-your-sale-price-on-shopify-no-code · Shakhawat Hossen · 2026-06-28 · Discounts & offers You've seen it on basically every store that runs sales: the old price with a line through it, sitting right next to the new, lower one. It's a small visual trick that does a lot of work, it tells a shopper at a glance that this isn't just a price, it's a deal, and deals move faster than plain prices do. Picture two identical product pages. One just says \$40. The other says \$65, crossed out, with \$40 next to it. The actual price a customer pays is the same on both, but the second one reads as a decision already made for them, they're not wondering if \$40 is reasonable, they're enjoying the fact that they're saving \$25. That framing effect is most of why this look is worth setting up at all. The good part is you don't need a developer or a single line of Liquid to get this look on your Shopify store. It's built into the platform already. The only real skill involved is knowing which field actually controls it and which method makes sense for how many products you're updating. One thing worth knowing before you start: Shopify already shows a crossed-out price automatically at checkout once a discount applies, that part is native and free, no setup required. What's not automatic is getting that same treatment to show up earlier, on the product page and collection pages, where a shopper actually decides whether to click "Add to cart" in the first place. That earlier moment is what this guide covers. ## The field behind the look Every product variant on Shopify has two price fields: Price, which is what the customer actually pays, and Compare at price, which is optional. When Compare at price is set higher than Price, your theme draws the strikethrough through the old number and shows the new one beside it. That's the entire mechanism. No app, no code, just two fields working together. Concretely: if a hoodie normally sells for \$65 and you want it to look like a sale at \$40, you set Price to 40 and Compare at price to 65. Leave Compare at price blank and the hoodie just looks like a \$40 hoodie, nothing crossed out, nothing implying a discount happened at all, even if \$40 genuinely is a markdown from where it used to sit. The three methods below are really just three different ways of filling in that same field, scaled to however many products you're touching. ## Method 1: One product at a time This is the right call for a single item or a small handful. 1. From your Shopify admin, go to **Products** and click the product you want to mark down. 2. In the **Pricing** section, find the **Compare at price** field and enter the original price. 3. In the **Price** field, enter the new, lower price. 4. Click **Save**. That's it, the strikethrough should now show on the live product page, assuming your theme renders it, more on that below. Two small things that trip people up here. First, if a product has multiple variants, this needs to be set per variant, a shirt in three sizes means three fields to fill in, not one. Second, Shopify treats a compare-at price of exactly \$0.00 differently from a genuinely empty field, if you're trying to remove a sale price later, make sure the field is actually cleared, not just zeroed out, or you may see inconsistent results across variants of the same product. ## Method 2: Shopify's built-in bulk editor Once you're updating more than a few products, clicking into each one individually gets old fast. Shopify has a spreadsheet-style bulk editor built right into the admin, no app, no export required. 1. From your Shopify admin, go to **Products**. 2. Use the checkboxes to select every product you want to put on sale. 3. Click **Edit products** (sometimes labeled **Bulk edit**) at the top of the list. 4. If the Compare-at price column isn't already visible, click **Columns** and add it. 5. Click into the first cell and enter the value. To apply the same number across several rows, click and drag the small square at the corner of the cell down through the rest, the same trick as Excel or Google Sheets autofill. 6. Click **Save**. This works well for sales touching anywhere from a handful up to a few dozen or so products comfortably. Past a certain catalog size, scrolling through a giant table in the browser stops being the fast option, and that's where the next method takes over. One practical limit worth knowing: very large selections can get slow to load and save in the bulk editor, so if a sale is touching most of a large catalog, it's usually faster to skip straight to the export and import method below rather than fighting with an oversized table in the browser. ## Method 3: CSV export and import, for bigger catalogs If you're marking down hundreds of products, or you want to prepare the whole thing in advance rather than sitting in the admin clicking cells, exporting to a spreadsheet is the more practical route. 1. From your Shopify admin, go to **Products** and click **Export**. Choose the products you want and download the CSV. 2. Open the file in Excel or Google Sheets. Find the column called **Variant Compare At Price**, and the **Variant Price** column next to it if you're changing the sale price too. 3. Fill in your values. Since it's a normal spreadsheet at this point, formulas work fine if you want to calculate a percentage off rather than typing each number by hand, something like `=B2*0.8` next to a 20%-off Variant Price column, with the original Variant Price values moved over into Variant Compare At Price, gets you there for an entire catalog in seconds rather than one product at a time. 4. Save the file as a CSV. 5. Back in Shopify admin, go to **Products** and click **Import**, then upload your edited file. You'll get a confirmation email once the import finishes processing. This same workflow is also the easiest way to schedule a sale ahead of time, prepare the file today, import it the morning the sale starts, rather than doing the actual editing live. ## A note on what your theme has to cooperate with Filling in the field is only half the job, your theme has to actually be checking for it and rendering the strikethrough. Most modern themes do this on the product page without any extra work. Collection pages are less consistent, plenty of themes show the markdown beautifully on a single product and skip it entirely on the grid view. If you've followed any of the three methods above and nothing's showing up, that's the next place to look, not the price fields themselves. If you're comfortable with code and want to fix that gap on the theme side rather than relying on these fields, that's a separate, more technical path involving your theme's Liquid templates, and outside the scope of a no-code guide like this one. Worth knowing it exists if a developer's available to you, not worth attempting if today's goal is getting a sale live in the next ten minutes. ## Why this is worth the few minutes it takes It's tempting to skip this step and just lower the price outright, no crossed-out number, just a smaller one. The problem is that a smaller number on its own doesn't tell a shopper anything about whether it's actually a deal. \$40 might be a great price or a mediocre one, nothing on the page says which. \$65 crossed out next to \$40 removes that ambiguity instantly, the comparison is built right into the page instead of left for the shopper to research elsewhere or just guess at. This is also exactly why discount codes alone often underperform compare-at pricing for driving urgency: a code is invisible until someone types it in, while a crossed-out price is doing its job the moment the page loads, before the shopper has decided whether to keep browsing or buy. ## The part none of these methods solve Here's the honest limitation across all three: none of them know when your sale is supposed to end. The compare-at price sits there until you, personally, go back in and clear it, one product, one bulk edit, or one more CSV import at a time. Forget that step and the "sale" just keeps running indefinitely, often discovered by a customer or a sharp-eyed coworker well after the fact. For a single short sale, that's a minor chore. For a store running markdowns regularly, it becomes the kind of small recurring task that's easy to deprioritize until it turns into an actual pricing mistake. This is the specific gap that apps in this space exist to close, watching your actual Shopify discounts and turning the visual on and off automatically instead of leaving it to memory. [Show Discount](https://apps.shopify.com/showdiscount) is the one I built for exactly this, a badge that syncs with your live discounts and clears itself the moment they end, with a free plan if you want to see whether it's worth handing the cleanup off entirely. ## Which method actually fits your situation A rough guide: one or two products on sale, do it manually inside the product page. A seasonal sale touching a few dozen items, the built-in bulk editor will get you there faster than you'd expect. Hundreds of SKUs or a sale you want to prep in advance, export to CSV and work from a spreadsheet. Running sales often enough that "remembering to revert it" has already bitten you once, that's the point where an app earns its keep. ## A few quick answers **Will this show up on collection pages too, or just the product page?** Depends entirely on your theme. Setting the field is the same either way, whether it renders on collection grids is a theme decision, not something the Compare at price field controls. **I don't see a Compare-at price column in the bulk editor, where did it go?** Click **Columns** in the bulk editor toolbar and add it. Shopify doesn't show every available field by default. **Does any of this change what the customer is actually charged?** No. Compare at price is purely visual. The amount charged at checkout always comes from the regular Price field, regardless of what the compare-at field says. **What if some variants of a product have it set and others don't?** Keep it consistent across all variants of the same product, mixed compare-at pricing on one product's variants is a common cause of strikethrough pricing looking right on one size or color and wrong on another. **Can I schedule this in advance so it goes live automatically?** Not with the native fields alone, they're static until you or a file you import changes them. The CSV method lets you prepare everything ahead of time, but you, or whatever's automating the import, still has to trigger it at the right moment. True scheduling, where it turns on and off by itself, is one of the things a dedicated app handles that the raw fields don't. --- ### Shopify Discount Code Not Applying at Checkout? Common Causes and Fixes URL: https://batinstudio.com/blog/shopify-discount-code-not-applying-at-checkout-common-causes-and-fixes · Shakhawat Hossen · 2026-06-28 · Cart & checkout A customer makes it all the way to checkout. They type in the code from your email, your Instagram caption, or the sticker on the box from their last order. They hit enter, expecting the total to drop, and instead get a flash of red text telling them something's wrong. That moment is expensive in a way that's easy to underestimate. The customer didn't abandon their cart over price, they abandoned it over confusion, and confusion at the very last step of checkout is the worst place for it to happen. You paid for the ad or the email that got them there, you got the offer right, and the sale dies on a technicality the customer can't see and probably can't explain to you afterward either, they just leave. The good news is that discount codes almost never fail randomly. Shopify's discount engine follows a strict, fairly predictable set of rules, and once you know what they are, tracking down why one specific code failed usually takes a couple of minutes, not a support ticket. Here's how to actually work through it. ## Start with the exact error message Shopify doesn't fail silently, it tells you something, even if it's not always obvious what that something means. There are three messages worth knowing: **"Enter a valid discount code."** This means Shopify doesn't recognize the code at all, or it does but it's expired, not yet started, or deactivated. This is a code problem, not a cart problem. **"\[CODE\] discount code isn't valid for the items in your cart."** The code exists and is active, but whatever's in the cart right now doesn't meet its conditions. This is almost always a cart problem, not a code problem, and it's the message that shows up most often. **"Some discount codes couldn't be used together. We applied the best combination."** The customer tried to use more than one code, and Shopify picked the better one instead of stacking them. More on why that happens below. If you're troubleshooting this for your own store, the message your test attempt produces tells you which of the next few sections to actually read. ## The eligibility mismatch, the most common cause by far Most failed codes aren't broken, they're working exactly as configured against a cart that doesn't qualify. A discount can be restricted by minimum purchase amount, by specific products or collections, by quantity, or by customer segment, and if the cart in front of you doesn't satisfy every condition attached, the code is correctly rejected. Say you've set "SAVE15" to require a \$75 minimum and you promoted it as a flat "15% off" without mentioning that threshold anywhere. A customer with a \$52 cart enters the code, gets rejected, and has no idea why, because nothing in your messaging told them there was a minimum at all. From their side it just looks broken. From Shopify's side it's working perfectly, the cart simply never qualified. The collection restriction catches people more than they'd expect. If a code is scoped to a "Summer Essentials" collection and a product technically belongs there but was added through an automated collection rule that hasn't run yet, the product can look like it's in the collection from the storefront while the discount engine sees it differently. Worth checking the collection's actual product list directly in admin, not just assuming. Customer segment restrictions have a quirk that trips up a lot of new-customer promotions specifically: a discount scoped to an existing segment only applies to people who already have a customer profile. A brand new shopper checking out for the very first time doesn't have a profile yet, so they won't be matched to a segment until after that first order completes, even if the segment is meant to describe exactly the kind of customer they are. If you're running a "first order" promotion and customers say it's not working, this is usually why. ## Only one code works at a time This one surprises a lot of people: Shopify only allows a single discount code to be entered per order. Customers can't stack two manual codes together no matter what either code allows individually, that's a platform rule, not a setting you can change. What you can control is whether a code combines with an automatic discount that's already running, or with another type of discount entirely. That's handled through the Combinations section at the bottom of each discount's settings. If you've got a site-wide automatic sale running and a customer tries to layer a code on top of it, and combinations aren't explicitly turned on, the code will fail or only partially apply, even though both look "active" from where you're sitting. If you're running more than one promotion at a time, it's worth actually testing the combination end to end before launch, since this is exactly where the math can quietly come out wrong and nobody notices until a customer points it out. A common version of this: you launch a site-wide automatic 10% off sale for the weekend, then send an email blast with a "WELCOME15" code for new subscribers. A subscriber tries to use it, and unless you've gone into both discounts and explicitly allowed them to combine, only one applies, usually whichever one Shopify determines is the better deal for that cart, and the customer never gets an explanation for why their email code "didn't work" when really it just lost out to a discount they couldn't see. ## Usage limits and who's allowed to use it A code can have a total redemption cap across the whole store, a limit of one use per customer, or both. Once either limit is hit, the code stops working even though it still shows as "Active" in the admin if you're not specifically looking at the usage count. The "one use per customer" version is usually tracked against the email or account on the order, which means a returning customer trying the same code a second time, even from a different device, will get rejected on purpose. That's frequently mistaken for a bug when it's actually the discount doing its job. ## The smaller things that quietly cause failures A handful of less obvious issues round out most of the rest: **Typos and stray characters.** Shopify discount codes aren't case sensitive, but a trailing space, a copy-pasted character, or letters that look alike (a capital O next to a zero, a lowercase l next to a 1) can still cause a mismatch. **Currency and Markets.** If a minimum spend is set in your store's main currency and a customer is shopping in a different market currency, the converted threshold can land a few cents off from what you'd expect, especially if you've set fixed regional pricing separately. **Draft orders.** If a code is supposed to work on an invoice sent through a draft order, the "Discount codes" option has to be checked when that invoice is created. Skip it, and no code will work on that order no matter how correctly it's configured. **Checkout customizations.** If you or an app have modified checkout behavior, the discount code field itself can disappear entirely for some customers. This is one of the few cases where the problem isn't the discount's settings at all, it's that the field never rendered. **Post-purchase upsells.** Discounts created in the Shopify admin aren't compatible with post-purchase offer pages. If a code is meant to apply somewhere in a post-purchase flow, that needs to come from whatever app is running that flow, not the native Discounts section. **BOGO specifically.** Buy X Get Y codes fail constantly for one simple reason: the customer added the X item but forgot the Y item, so the cart never met the condition in the first place. **The hidden mobile field.** On a lot of mobile checkouts, the discount code field lives inside a collapsed order summary that the customer has to tap open first. If they never expand it, it's not that the code failed, it's that they never found anywhere to enter it. **The wrong box entirely.** Some checkout themes show a gift card field alongside or instead of an obvious discount field, and customers occasionally try typing a promo code into the gift card box, where it will never validate no matter how correct it is. ## A quick way to actually diagnose it 1. Note the exact error message, it tells you which section above to check first rather than making you guess. 2. Open the discount in admin and confirm it's Active, not scheduled for later or already expired. 3. Check every restriction on it: minimum purchase, specific products or collections, customer segment, usage limits, all of them, not just the first one you spot. 4. Build a fresh cart with only the eligible items and test again before assuming anything else is wrong, half of these issues disappear the moment you control exactly what's in the cart. 5. If another discount or automatic sale is also running, check the Combinations setting on both, not just the one you're testing. 6. If the code field is missing entirely rather than rejecting the code, look at recently installed or recently updated checkout apps first, since a missing field points to the checkout itself rather than the discount's rules. ## The easiest long-term fix A lot of this entire category of problem only exists because the customer has to type something correctly, into a small field, on the page where they're trying to finish buying something. Remove the typing and most of these failure points disappear with it. That's the part [Show Discount's](https://apps.shopify.com/showdiscount) Pro plan handles directly: it auto-applies your discount codes at checkout instead of waiting for a customer to enter one manually. No field to mistype into, no case mix-ups, no copy-paste errors from an email that wrapped the code across two lines. If code friction has been showing up in your support inbox more than you'd like, it's worth a look, the free plan's there to try the basics first. ## A few quick answers **Why does it say my code isn't valid when I know it's active?** "Active" only means the dates and status are correct. It says nothing about whether the current cart meets the code's other conditions, that's a separate check. **Can a customer use two discount codes at once?** No. Shopify allows one manual code per order. A code can combine with an automatic discount if you've explicitly allowed that combination, but two manual codes can't stack. **Why did it work for one customer and not another with the identical cart?** Check usage limits and customer segment restrictions first, those are the two conditions that vary by customer rather than by cart contents. **Is there a way to see why a specific failed attempt happened, after the fact?** Not in detail from the native admin. Shopify shows the customer an error in the moment, but it doesn't log a per-attempt reason you can look up later. If this happens often enough to matter, the practical fix is testing the exact scenario yourself rather than trying to reconstruct someone else's failed checkout. If you've worked through all of this and the code is still failing on a cart that genuinely should qualify, that's the point to test on a duplicate theme with other apps disabled one at a time, since at that stage it's more likely to be a checkout customization conflict than a discount setting. --- ### Why Aren't My Shopify Discounts Showing on the Product Page? URL: https://batinstudio.com/blog/why-arent-my-shopify-discounts-showing-on-the-product-page · Shakhawat Hossen · 2026-06-28 · Discounts & offers You set up the discount. You double checked the percentage. You hit save, popped open the storefront in a new tab, and... nothing. Same price as before. No strikethrough, no badge, no sign that anything changed at all. If you're in that exact moment right now, the first thing worth knowing is that you almost certainly didn't break anything. This is one of the most common points of confusion in Shopify, and it trips up store owners who've been running their shop for years, not just people setting up their first sale. The reason isn't usually a bug. It's that Shopify treats "having a discount" and "showing a discount" as two completely separate jobs, and most people only find that out the hard way. Let's go through why that happens, then how to actually fix it for your store. ## Discounts and prices are two different systems Here's the part that catches almost everyone off guard: when you create a discount through Shopify's Discounts section, whether it's an automatic discount or a code, you're not editing the product's price. You're creating a rule that gets calculated later, usually at the cart or checkout step, when Shopify works out the final total. That's a deliberate design choice, not an oversight. Discount codes obviously can't show up early, since Shopify has no way of knowing which code a browsing customer might type in later. But automatic discounts trip people up more, because they feel like they should just work. You set "20% off all hoodies," you assume the hoodie page will now show 20% off, and instead the price sits there completely unchanged until the customer adds it to their cart. Picture a \$50 hoodie with that 20% off automatic discount turned on. A customer opens the product page and sees \$50, exactly as before. They add it to the cart, and the line item drops to \$40. Nothing on the way there told them a discount existed at all, they only find out once the math has already happened behind the scenes. That's not broken, that's the discount engine doing exactly what it was built to do, just not the job most people assume it's doing. The product page price and the discount engine simply aren't talking to each other by default. One displays what's stored on the product. The other calculates a total at checkout. Nothing connects them automatically unless something is specifically built to do that. ## The "Compare at price" field is the actual mechanism If discounts don't update the displayed price, what does? A separate field called Compare at price. Every product variant in Shopify has two price fields: the regular price, and an optional compare at price. When the compare at price is higher than the regular price, your theme draws a strikethrough through the old number and shows the new one next to it, the classic "\$50 → \$40" look. This is what most people actually picture when they imagine a discount showing on the product page. The catch is that creating a discount in the Discounts section does not fill in this field for you. They're unrelated settings that happen to produce a similar visual outcome when both are set up correctly. If you want that markdown look on a product page, you either set the compare at price manually on every variant, or you use something that does it for you automatically. This is also why two stores can run what looks like an identical 30% off sale and have completely different storefront results. One has the compare at price set and shows the strikethrough everywhere. The other only has the automatic discount turned on, and the price looks untouched until checkout. ## Your theme has a say in this too Even once the compare at price is set correctly, what happens next depends on your theme's code. Most modern themes check for a compare at price and render it automatically on the product page, and a lot of them do the same on collection pages. But "most" isn't "all," and the logic isn't always consistent across every page type in the same theme. It's common to see a theme that handles this perfectly on the product page but completely ignores it on collection grids, or vice versa. Heavily customized themes, older themes, and themes that were built before a recent redesign are the most frequent offenders. If you've set the compare at price and you're still not seeing anything, the theme's product template is the next place to look, specifically whether it has logic checking for a compare_at_price value at all. This is also where third-party apps sometimes step on each other. If you've got more than one discount or pricing app installed, it's worth checking whether one of them is quietly overriding what another is trying to display. ## If you want to fix it in the theme code yourself For the technically inclined, this is a Liquid problem at its core. Most product templates have a line that looks roughly like this: {{ product.price | money }} {% if product.compare_at_price > product.price %} {{ product.compare_at_price | money }} {% endif %} That's the logic deciding whether to draw the strikethrough at all. If your theme is missing this check entirely, or it's only present on one template and not another, that's your answer right there, and adding it is usually a small, contained edit. The harder version of this is trying to make an *automatic* discount drive that same display without ever touching the compare at price field. That means writing logic that calculates the discounted price live, on every page where you want it shown, and keeping that logic in sync with whatever rules exist in your Discounts admin. It's doable, but it's real ongoing maintenance, not a one time fix, especially once you're running more than one promotion or the discount rules change from month to month. This is usually the point where a developer either builds something custom or reaches for an app instead. ## Other reasons your discount might be invisible Once you've ruled out the big one above, a handful of smaller issues account for most of the rest: **Timing and scheduling.** Discounts can be scheduled to start and end at specific times, and timezone mismatches between your store settings and your own clock are an easy way to think something is live when it technically isn't yet. **Scope.** A discount can be limited to specific products, specific collections, or specific customer segments. If you're checking a product that wasn't included, or you're not logged in as the customer type the discount applies to, you won't see it, and that's working exactly as configured. **Minimum requirements.** Some discounts only kick in above a certain order value. Looking at a single product page in isolation will never trigger a discount that depends on cart totals, since that condition can't be evaluated until there's an actual cart. **Combination settings.** Shopify lets you control whether discounts can stack with each other through a "Combinations" setting on each discount. If a higher priority discount is set to not combine with others, it can silently override the one you're expecting to see. **Markets and currency.** If you sell in multiple markets or currencies, a discount created in one context doesn't automatically apply everywhere. It's worth checking the storefront in the specific market you're testing. **Usage limits.** Discounts can have a total redemption cap. Once that's hit, the discount stops applying even though it still looks "active" in the admin if you don't check the usage count specifically. **B2B and wholesale catalogs.** Some discounts are scoped to specific company accounts or B2B price lists. They'll never show up for a regular logged out visitor, by design, no matter how active they are. **Caching.** Rare, but real. Browser cache, a CDN, or even your own habit of checking the same tab you had open before the change can show you a stale version of the page. A hard refresh or an incognito window rules this out in ten seconds. ## A quick way to actually diagnose it Rather than guessing, work through this in order: 1. Open the discount in your Shopify admin. Confirm it's active right now, not scheduled for later or already ended. 2. Check whether it's an automatic discount or a code. Codes are expected to be invisible until entered, that's not a bug. 3. Open the specific product you're testing and check its compare at price field. Is it actually set, and is it higher than the current price? 4. If the compare at price is set correctly and it's still not showing, the issue is almost certainly in your theme's code, and it's worth a quick test on a duplicate theme to confirm before changing anything live. 5. Test in an incognito window to remove caching as a variable. Most cases resolve somewhere in steps one through three. ## Where the manual fix breaks down Once you know the compare at price field is what actually drives the visual, the obvious move is to just set it yourself on every product whenever you run a sale. That works, for a small catalog and a short sale. It gets messy fast at any real scale. You have to remember to set it before the sale starts, remember to revert it the moment the sale ends, and do that across every product the discount touches. Forget the second part and you end up with a "sale" that quietly never expires, sitting there until a customer or a sharp eyed coworker points it out. Run a few overlapping promotions a year and the bookkeeping alone becomes its own small job. That gap, between having a discount and reliably showing it without babysitting a spreadsheet of price fields, is exactly the problem I built [Show Discount](https://apps.shopify.com/showdiscount) to close. It watches your actual Shopify discounts and shows a badge next to the price automatically the moment one goes live, then takes it down the moment it ends. No manual price editing, nothing to remember to undo. If you've read this far because you're staring down exactly this problem, it's worth a look, the free plan covers unlimited product page badges and there's no card required to try it. ## A few quick answers **Will setting the compare at price myself work without any app?** Yes, for product pages on most modern themes. It just doesn't scale well or sync itself when the sale ends, which is the part most stores eventually want solved. **Why does my discount show in the cart but not on the product page?** That's the expected behavior for automatic discounts and codes. The cart and checkout calculate the final total directly. The product page only shows what's stored in its price fields, which a discount rule doesn't touch. **Could a different app be interfering?** Yes, especially if you're running more than one pricing, bundling, or discount app at once. If your compare at price is set correctly and it's still not showing, try disabling other pricing related apps one at a time to isolate the conflict. **It shows on the product page but not on collection pages, what's going on?** That's a theme issue, not a discount issue. Plenty of themes check for compare at price on the product template but skip that same check on collection grids. The fix lives in the theme's collection template code, not in your discount settings. If none of this fixes it after working through the checklist, the remaining cases are usually theme specific, and at that point it's worth pulling in a developer who can read the actual product template rather than guessing further from the admin side. --- ### 69% of Shoppers Abandon Their Cart Before Buying. Here's the Real Reason Why. URL: https://batinstudio.com/blog/69-of-shoppers-abandon-their-cart-before-buying-heres-the-real-reason-why · Shakhawat Hossen · 2026-06-27 · Cart & checkout Picture a customer. She found your product through an Instagram ad, clicked through, scrolled your product page for a good forty seconds, read a few reviews, picked her size, and tapped "Add to Cart." She was sold. Then she got to checkout, saw a shipping fee she wasn't expecting, raised an eyebrow, and closed the tab. You never heard from her again. Not because she didn't want the product. Because something between "yes" and "pay" got in her way, and she didn't think it was worth fighting through. This happens more than most store owners want to admit. Roughly 7 out of every 10 people who add something to their cart leave without buying it. That's not a scare tactic from a marketing blog. It's the average across more than 50 independent studies tracked by the Baymard Institute, the closest thing ecommerce has to a research authority on this exact problem. The number has sat somewhere in the high 60s to low 70s for over a decade. It drifts a point or two year to year, but it never really moves. That's the interesting part. Checkout technology has gotten faster over that same decade. Shop Pay exists. One-click buying exists. Apple Pay sits right there on every phone, ready to skip the entire form. And still, the number hasn't budged. If better checkout tools were the whole answer, abandonment would have dropped by now. It hasn't. Which tells you the problem isn't really about technology. It's about what happens in the seconds between "I want this" and "I paid for this." That gap between wanting and buying is what this post is about. ## The number that refuses to move Let's sit with that stat for a second, because it's easy to read past it. 69 to 70 percent abandonment means that for every 10 people who fill a cart on your store, only 3 actually finish the order. If your product pages and ads are doing their job, you're already winning the hard part: getting a stranger to want something enough to click "add to cart." Then you lose 7 out of 10 of them anyway, right at the finish line. For a store doing \$50,000 a month in completed sales, that math is brutal to think about. If even a modest slice of that abandoned 70% had gone through, you could be looking at a business doing two or three times the revenue, with the exact same traffic, the exact same ad spend, and the exact same products. Nothing about your marketing changes. Nothing about your product changes. Just the experience between clicking "buy" and actually buying. That's the part that should bother you more than a slow month of traffic. Traffic is expensive to fix. You have to spend money on ads, build an audience, earn organic reach, or wait for word of mouth to grow. Checkout friction just sits there, free to fix. Most stores never go looking for it because nothing about a lost cart feels like an emergency. There's no error message. No support ticket. The customer just quietly leaves, and the store rarely finds out why. That silence is exactly why this problem survives so long inside otherwise well-run businesses. You can run a great ad campaign, write great product copy, and ship a great product, and still leak most of your potential revenue through a checkout flow nobody has looked at critically in a year. ## Most of that 69% was never going to buy anyway Here's the part that gets left out of most scary stats on this topic. It matters because it keeps you from chasing the wrong fix. Not everyone who adds something to a cart is a lost sale. A meaningful chunk of shoppers use the cart the way you'd use a sticky note. They're comparing two jackets across three tabs. They're checking if something fits their budget before payday. They're window shopping with intent, which is a real and common behavior, not a failure of your store. Baymard's own research puts the share of abandoners who were simply browsing, not ready to buy, or saving something for later somewhere between 40 and 60 percent, depending on the study. That portion isn't really yours to win back. No amount of clever checkout design turns "just looking" into "just bought." A shopper who added a jacket to her cart on a Tuesday, with no plan to buy until payday, was never going to convert that night. It doesn't matter how smooth your checkout is. Chasing that segment with discount popups and urgency banners usually just trains your most price-sensitive shoppers to wait for a deal, which is its own slow problem. But that leaves the other half. The shoppers who had genuine intent, who were ready to pay, and who left anyway because something in your store got in the way. That's the group worth obsessing over. Baymard's checkout usability research suggests stores can realistically recover around a third of those losses through better checkout design alone. No new traffic. No new ad budget. No discount codes. Just removing friction that shouldn't have been there in the first place. So the real question isn't "how do I get to 0% abandonment." Nobody gets there, and chasing it is a waste of energy. The real question is: of the people who actually wanted to buy, how many did your store accidentally talk out of it? ## What's actually fixable A handful of reasons show up again and again across every major study on this topic. Almost all of them are design problems, not pricing or product problems. Here's what's actually driving the abandonment you can control. ## 1. The shipping fee plot twist This is the single biggest fixable cause of cart abandonment, and it has held that position for years running. Close to half of shoppers who abandon a cart blame unexpected costs: shipping fees, taxes, or handling charges that appear for the first time at checkout. The product was \$42. They were fine with \$42. Then checkout adds \$9.95 for shipping and suddenly the total feels different, even though nothing about the product changed. That jump from "the price I agreed to" to "a higher price I didn't agree to" is where trust quietly breaks. It's not really about the \$9.95. It's about feeling like the number changed without warning. That makes a shopper wonder what else might change before checkout is done. The fix isn't complicated. It's just rarely done properly. Show the real cost early. Put shipping rates on the product page or the cart page, not buried until step three of checkout. If you offer free shipping above a certain order value, say so loudly and often. "You're \$8 away from free shipping" does double duty: it removes the surprise and it nudges people to add one more item to clear the threshold. Stores that do this see lower abandonment and a small lift in average order value. That's about as close to a free win as ecommerce gets. If you sell internationally, the same logic applies to duties and customs fees. They catch even more people off guard than domestic shipping ever does. ## 2. The checkout that asks too many questions Open your own checkout flow right now and count the form fields. If you're like most stores, you'll land somewhere around 20 to 25. The research on this is blunt: the ideal checkout needs roughly 12 to 14 form elements. Most stores could cut their field count by 20 to 60 percent without losing a single piece of information they actually need. Every extra field is a tiny tax on someone's patience. A phone number field with no explanation for why it's required. A "company name" field on a personal order. An address line 2 that's mandatory when it should be optional. None of these feel like a big deal individually. Stacked together, on a small phone screen, with a thumb doing the typing, they add up to "this is taking longer than I expected." That thought is exactly when people bail. Go through your checkout like you've never seen it before. For every field, ask one question: do we actually need this to fulfill the order? If the answer is "it would be nice to have for marketing later," cut it. You can always ask after the sale, once there's already a relationship. People are far more willing to hand over an extra detail to someone they've just bought from than to someone they're still deciding whether to trust. ## 3. The login wall Few things kill momentum faster than "Please create an account to continue." A shopper who was three taps from paying suddenly has to think of a password, confirm an email, and decide whether they trust you enough to become a member of something. Some of them will do it. A noticeable number will close the tab instead, not because they changed their mind about the product, but because the request felt bigger than the moment called for. Guest checkout exists for exactly this reason. Stores that offer it as the default, not as a hidden link under a more prominent "Create account" button, see meaningfully lower abandonment. You can still capture the email and invite them to create an account after the order is placed. By then they're already a customer, and the ask feels like a natural next step instead of a toll booth. ## 4. The page that doesn't feel safe This one is subtle and easy to miss, because it's not one broken thing. It's the absence of several small reassurances that add up to confidence. No visible security badge near the payment field. No mention of a return policy anywhere close to checkout. No recognizable payment logos. A site that looks fine but gives a shopper nothing concrete to point to and say "yes, this feels legitimate." Most people aren't consciously auditing your trust signals. But somewhere in the back of their mind, right as they're about to type in a card number, a quiet question runs through their head: is this safe? If your page answers that question before they have to ask it, the moment passes without friction. If it doesn't, hesitation creeps in. Hesitation at checkout is almost always fatal to the sale, because it gives someone a reason to think "I'll come back to this later." Later rarely comes. A secure checkout badge, a clear returns policy, recognizable payment icons: these cost nothing to add, and they answer a real objection most stores never bother to address out loud. ## 5. The phone problem Mobile abandonment runs well above desktop, often 10 to 15 percentage points higher. That gap matters now that well over 60% of ecommerce traffic comes from a phone. A checkout flow that feels fine on a laptop can feel genuinely painful on a 6 inch screen: tiny tap targets, a keyboard that covers half the form, fields that don't trigger the right type of input. A phone number field should pull up the number pad automatically. An email field should bring up the @ symbol within easy reach. Small details, but they're the difference between a checkout that feels effortless and one that feels like work. If you haven't bought something from your own store, on your own phone, in the last month, do it today. Not a glance, an actual purchase, card details and all. Most of the friction missed in a design review only shows up when your own thumb is doing the work, fumbling with a button that's too small or a dropdown that's awkward to tap. ## 6. The coupon code rabbit hole This one is sneaky because it looks harmless. A checkout field that says "Have a discount code?" sits right above the payment button. A shopper with no code at all suddenly wonders if she's missing one. She opens a new tab, searches "\[your store name\] coupon code," and lands on a deals site. One ad later, she's distracted by another offer entirely and never makes it back to finish the order she'd already half completed. You didn't lose her over price. You lost her because you reminded her, at the worst possible moment, that codes exist. The fix isn't to remove the field entirely if you run promotions regularly, but to stop making it loud and prominent by default. A small, collapsed "Have a promo code?" link that expands when clicked does the same job without putting the idea in front of everyone who wasn't already looking for a deal. ## The safety net: recovery, not just prevention Even with every fix above in place, some carts will still go cold. That's normal, and it's where abandoned cart emails earn their keep. They're not a replacement for fixing your checkout. Think of them as the net underneath it, catching people who got distracted, lost signal, or genuinely meant to come back and forgot. A simple three-email sequence over the following few days recovers a real, measurable slice of otherwise lost orders. The first, sent within an hour or two, is a gentle reminder: the cart is still there, here's what's in it. The second, a day later, can address a likely objection directly, whether that's free shipping, your return policy, or a quick answer to "is this worth it." The third, a few days out, is where a small, time-limited incentive can make sense. Not because everyone needs a discount to buy, but because for the shopper genuinely on the fence, a nudge at the right moment is sometimes all that's missing. It's worth being honest about what recovery emails can and can't do. They work well on the genuinely interested shopper who got pulled away by life. They don't do much for the shopper who was only ever browsing. And no subject line fixes a checkout that's fundamentally too slow or too confusing. Treat recovery as the second layer, not the first. Fix the friction, then catch what's left. The timing matters more than most stores realize. Send that first email too fast, within minutes, and it feels like you're watching them. Send it too slow, a few days later, and the moment has passed. They've either bought it elsewhere or forgotten what they wanted. An hour or two is usually the sweet spot: close enough that the product is still fresh, far enough that it doesn't feel like a notification fired the instant they closed the tab. The subject line matters too. "You left something behind" reads warmer than "Complete your order," because one sounds like a person noticed and the other sounds like a system did. ## The part that's worth saying plainly None of this is about tricking anyone into buying something they don't want. It's the opposite. A shopper who already decided to buy, who's holding their card, deserves a checkout that gets out of their way instead of quietly testing their patience. Every fix above is really just removing an obstacle that was never supposed to be there. It's also worth saying that this isn't a one-time fix you check off a list and forget. Shipping rates change. New form fields get added by some app you installed eight months ago and forgot about. A theme update shifts a button by a few pixels and suddenly it's not obvious on mobile anymore. The stores that keep their abandonment rate below average aren't the ones who fixed it once. They're the ones who treat their checkout the way they'd treat a physical storefront, walking through it regularly, noticing what's changed, and fixing the small things before they become the reason someone leaves. If there's one habit worth building from this post, it's that. Go through your own checkout, on your phone, once a month, as if you've never seen it before. You'll catch more than you'd expect. Most of what you find will be free to fix. ## Where Batin Studio fits into this This is the kind of work we do constantly for Shopify stores: walking through a checkout flow line by line, finding the exact moment a real buyer gets quietly talked out of buying, and fixing it. Not a redesign for the sake of a redesign. Specific, fixable friction, removed one screen at a time, until the path from "add to cart" to "thank you for your order" feels obvious instead of like an obstacle course. If you've read this far, wondering whether your own store has any of these six problems, that's worth listening to. Most owners know their store too well to see it the way a first-time visitor does. That's exactly why a second pair of eyes catches things you'd scroll right past. We're happy to take a look and tell you honestly what we find, no obligation attached. [Book a CRO call](/book). --- ### How to Self-Host Plane (Community Edition) on Coolify URL: https://batinstudio.com/blog/how-to-self-host-plane-community-edition-on-coolify · Shakhawat Hossen · 2026-04-22 · Notes If your team is paying \$5,000–\$6,000 a year for project management software and you're not using half its features, this guide is for you. [Plane](https://plane.so/) is an open-source project management tool that looks and feels like a modern SaaS product — boards, cycles, modules, timelines, dashboards — but runs entirely on your own server, for free. No per-seat pricing. No vendor lock-in. Your data stays yours. This tutorial walks you through deploying Plane's Community Edition on a server running [Coolify](https://coolify.io/) — a self-hosted platform that makes deploying Docker-based apps straightforward, even if you've never touched a terminal before. > **What you'll end up with:** A fully working Plane instance accessible at your own domain (e.g. `plane.yourdomain.com`), with SSL, running completely free on your own infrastructure. ------------------------------------------------------------------------ ## Prerequisites Before you start, make sure you have the following in place: - **A server running Coolify.** This guide assumes Coolify is already installed and accessible. If not, follow the [official Coolify installation guide](https://coolify.io/docs/installation) first. - **A domain name** with access to your DNS settings. You'll need to create an A record pointing a subdomain (e.g. `plane.yourdomain.com`) to your server's IP address. If you're unsure how to do this, refer to [Coolify's DNS configuration guide](https://coolify.io/docs/knowledge-base/dns-configuration). - **SSH access to your server.** You'll need to run a few commands directly on the server. Coolify's built-in terminal (under Servers → Terminal) works fine if you don't have a separate SSH client. - **Server specs:** Minimum 2 CPU cores and 4 GB RAM. ------------------------------------------------------------------------ ## Step 1 — Point Your Domain to Your Server Before anything else, create a DNS A record for the subdomain you want to use. 1. Log in to your domain registrar or DNS provider (e.g. Cloudflare, Namecheap, GoDaddy). 2. Create an **A record**: - **Name:** `plane` (or whatever subdomain you want) - **Value:** Your server's public IP address - **TTL:** Auto or 300 To find your server's public IP, SSH into your server and run: ``` bash curl -4 ifconfig.me ``` The output is your server's public IP. Use that as the value for your A record. > DNS changes can take a few minutes to an hour to propagate. You can continue with the rest of the setup while you wait. ------------------------------------------------------------------------ ## Step 2 — Gather Your Server's Docker Network Information Later in this guide, you'll need to connect Coolify's built-in proxy (Traefik) to Plane's Docker network. To do this, you need two pieces of information from your server: your **Docker gateway IP** and the ability to identify Plane's **Docker network ID** after deployment. Run this command to find the Docker gateway IP for the Coolify network: ``` bash sudo docker network inspect coolify | grep Gateway ``` You'll see output like: "Gateway": "10.0.2.1" **Write this IP down.** You'll need it later when configuring the Traefik proxy rule. ------------------------------------------------------------------------ ## Step 3 — Create the Docker Compose File In Coolify, navigate to your **Project → New Resource → Docker Compose Empty**. Paste the following compose file exactly as shown. This is a production-ready configuration with Plane's proxy service binding to port **8090** on the host (instead of the default 80/443), so it doesn't conflict with Coolify's own proxy which already owns those ports. ``` yaml x-db-env: &db-env PGHOST: ${PGHOST:-plane-db} PGDATABASE: ${PGDATABASE:-plane} POSTGRES_USER: ${POSTGRES_USER:-plane} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-plane} POSTGRES_DB: ${POSTGRES_DB:-plane} POSTGRES_PORT: ${POSTGRES_PORT:-5432} PGDATA: ${PGDATA:-/var/lib/postgresql/data} x-redis-env: &redis-env REDIS_HOST: ${REDIS_HOST:-plane-redis} REDIS_PORT: ${REDIS_PORT:-6379} REDIS_URL: ${REDIS_URL:-redis://plane-redis:6379/} x-minio-env: &minio-env MINIO_ROOT_USER: ${AWS_ACCESS_KEY_ID:-access-key} MINIO_ROOT_PASSWORD: ${AWS_SECRET_ACCESS_KEY:-secret-key} x-aws-s3-env: &aws-s3-env AWS_REGION: ${AWS_REGION:-} AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-access-key} AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-secret-key} AWS_S3_ENDPOINT_URL: ${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000} AWS_S3_BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads} x-proxy-env: &proxy-env APP_DOMAIN: ${APP_DOMAIN:-plane.yourdomain.com} FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880} CERT_EMAIL: ${CERT_EMAIL:-} CERT_ACME_CA: ${CERT_ACME_CA:-} CERT_ACME_DNS: ${CERT_ACME_DNS:-} LISTEN_HTTP_PORT: ${LISTEN_HTTP_PORT:-8090} LISTEN_HTTPS_PORT: ${LISTEN_HTTPS_PORT:-443} BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads} SITE_ADDRESS: ${SITE_ADDRESS:-:80} x-mq-env: &mq-env RABBITMQ_HOST: ${RABBITMQ_HOST:-plane-mq} RABBITMQ_PORT: ${RABBITMQ_PORT:-5672} RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-plane} RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-plane} RABBITMQ_DEFAULT_VHOST: ${RABBITMQ_VHOST:-plane} RABBITMQ_VHOST: ${RABBITMQ_VHOST:-plane} x-live-env: &live-env API_BASE_URL: ${API_BASE_URL:-http://api:8000} LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY} x-app-env: &app-env WEB_URL: ${WEB_URL:-https://plane.yourdomain.com} DEBUG: ${DEBUG:-0} CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-https://plane.yourdomain.com} GUNICORN_WORKERS: 1 USE_MINIO: ${USE_MINIO:-1} DATABASE_URL: ${DATABASE_URL:-postgresql://plane:plane@plane-db/plane} SECRET_KEY: ${SECRET_KEY} AMQP_URL: ${AMQP_URL:-amqp://plane:plane@plane-mq:5672/plane} API_KEY_RATE_LIMIT: ${API_KEY_RATE_LIMIT:-60/minute} MINIO_ENDPOINT_SSL: ${MINIO_ENDPOINT_SSL:-0} LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY} services: web: image: makeplane/plane-frontend:${APP_RELEASE:-stable} deploy: replicas: ${WEB_REPLICAS:-1} restart_policy: condition: any depends_on: - api - worker space: image: makeplane/plane-space:${APP_RELEASE:-stable} deploy: replicas: ${SPACE_REPLICAS:-1} restart_policy: condition: any depends_on: - api - worker - web admin: image: makeplane/plane-admin:${APP_RELEASE:-stable} deploy: replicas: ${ADMIN_REPLICAS:-1} restart_policy: condition: any depends_on: - api - web live: image: makeplane/plane-live:${APP_RELEASE:-stable} environment: <<: [*live-env, *redis-env] deploy: replicas: ${LIVE_REPLICAS:-1} restart_policy: condition: any depends_on: - api - web api: image: makeplane/plane-backend:${APP_RELEASE:-stable} command: ./bin/docker-entrypoint-api.sh deploy: replicas: ${API_REPLICAS:-1} restart_policy: condition: any volumes: - logs_api:/code/plane/logs environment: <<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env] depends_on: - plane-db - plane-redis - plane-mq worker: image: makeplane/plane-backend:${APP_RELEASE:-stable} command: ./bin/docker-entrypoint-worker.sh deploy: replicas: ${WORKER_REPLICAS:-1} restart_policy: condition: any volumes: - logs_worker:/code/plane/logs environment: <<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env] depends_on: - api - plane-db - plane-redis - plane-mq beat-worker: image: makeplane/plane-backend:${APP_RELEASE:-stable} command: ./bin/docker-entrypoint-beat.sh deploy: replicas: ${BEAT_WORKER_REPLICAS:-1} restart_policy: condition: any volumes: - logs_beat-worker:/code/plane/logs environment: <<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env] depends_on: - api - plane-db - plane-redis - plane-mq migrator: image: makeplane/plane-backend:${APP_RELEASE:-stable} command: ./bin/docker-entrypoint-migrator.sh deploy: replicas: 1 restart_policy: condition: on-failure volumes: - logs_migrator:/code/plane/logs environment: <<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env] depends_on: - plane-db - plane-redis plane-db: image: postgres:15.7-alpine command: postgres -c 'max_connections=1000' deploy: replicas: 1 restart_policy: condition: any environment: <<: *db-env volumes: - pgdata:/var/lib/postgresql/data plane-redis: image: valkey/valkey:7.2.11-alpine deploy: replicas: 1 restart_policy: condition: any volumes: - redisdata:/data plane-mq: image: rabbitmq:3.13.6-management-alpine deploy: replicas: 1 restart_policy: condition: any environment: <<: *mq-env volumes: - rabbitmq_data:/var/lib/rabbitmq plane-minio: image: minio/minio:latest command: server /export --console-address ":9090" deploy: replicas: 1 restart_policy: condition: any environment: <<: *minio-env volumes: - uploads:/export proxy: image: makeplane/plane-proxy:${APP_RELEASE:-stable} deploy: replicas: 1 restart_policy: condition: any environment: <<: *proxy-env ports: - target: 80 published: 8090 protocol: tcp mode: host volumes: - proxy_config:/config - proxy_data:/data depends_on: - web - api - space - admin - live volumes: pgdata: redisdata: uploads: logs_api: logs_worker: logs_beat-worker: logs_migrator: rabbitmq_data: proxy_config: proxy_data: ``` > **Why port 8090?** Coolify's Traefik proxy already listens on ports 80 and 443. If Plane's internal proxy tried to bind to those same ports, the deployment would fail with a port conflict. We use 8090 as a free internal port, and Traefik handles the public-facing traffic on 80/443 and forwards it to Plane. ------------------------------------------------------------------------ ## Step 4 — Configure the Environment Variables In Coolify, go to your service's **Environment Variables** tab and add the following. Replace all values marked with `YOUR_...` with your actual values. ``` # ── Domain ──────────────────────────────────────────────── APP_DOMAIN=plane.yourdomain.com APP_RELEASE=stable WEB_URL=https://plane.yourdomain.com CORS_ALLOWED_ORIGINS=https://plane.yourdomain.com # ── Proxy ───────────────────────────────────────────────── LISTEN_HTTP_PORT=8090 LISTEN_HTTPS_PORT=443 SITE_ADDRESS=:80 MINIO_ENDPOINT_SSL=0 # ── Security (generate your own random strings) ─────────── SECRET_KEY=YOUR_RANDOM_64_CHARACTER_STRING LIVE_SERVER_SECRET_KEY=YOUR_RANDOM_32_CHARACTER_STRING # ── Database ────────────────────────────────────────────── PGHOST=plane-db PGDATABASE=plane POSTGRES_USER=plane POSTGRES_PASSWORD=plane POSTGRES_DB=plane POSTGRES_PORT=5432 PGDATA=/var/lib/postgresql/data DATABASE_URL=postgresql://plane:plane@plane-db/plane # ── Redis ───────────────────────────────────────────────── REDIS_HOST=plane-redis REDIS_PORT=6379 REDIS_URL=redis://plane-redis:6379/ # ── RabbitMQ ────────────────────────────────────────────── RABBITMQ_HOST=plane-mq RABBITMQ_PORT=5672 RABBITMQ_USER=plane RABBITMQ_PASSWORD=plane RABBITMQ_VHOST=plane AMQP_URL=amqp://plane:plane@plane-mq:5672/plane # ── Storage ─────────────────────────────────────────────── USE_MINIO=1 AWS_ACCESS_KEY_ID=access-key AWS_SECRET_ACCESS_KEY=secret-key AWS_REGION= AWS_S3_ENDPOINT_URL=http://plane-minio:9000 AWS_S3_BUCKET_NAME=uploads FILE_SIZE_LIMIT=5242880 # ── Other ───────────────────────────────────────────────── DEBUG=0 API_BASE_URL=http://api:8000 API_KEY_RATE_LIMIT=60/minute ``` **Generating secret keys:** You need two secure random strings. Run this command on your server to generate each one: ``` bash openssl rand -hex 32 ``` Run it twice — once for `SECRET_KEY` and once for `LIVE_SERVER_SECRET_KEY`. Copy each output and paste it as the value. > **Important:** Never share these keys publicly. They are used to sign sessions and authenticate internal services. ------------------------------------------------------------------------ ## Step 5 — Deploy Click **Deploy** in Coolify. The first deployment pulls all Docker images, which may take 3–5 minutes depending on your server's internet speed. Once deployed, you'll see all services listed in the Logs tab. Don't worry if Coolify shows the service as **"Degraded (unhealthy)"** — this is expected. Coolify cannot health-check manually deployed Docker Compose stacks the same way it does its native resources. What matters is that the individual containers are running, which you can verify in the Logs tab. Look for these indicators that everything is healthy: - **Migrator** — should show `No migrations to apply` and then exit. This is normal — it's a one-time job. - **API** — should show `Starting gunicorn` and `Listening at: http://0.0.0.0:8000` - **Web, Admin, Space** — should show health check requests every 30 seconds - **Worker / Beat Worker** — should show `Connected to amqp://` - **Live** — should show `Express server has started at port 3000` - **Plane DB** — should show `database system is ready to accept connections` - **Plane Redis** — should show `Ready to accept connections tcp` ------------------------------------------------------------------------ ## Step 6 — Configure Traefik to Route Your Domain to Plane This is the most important step. Coolify uses Traefik as its reverse proxy — the service that receives all traffic on ports 80 and 443 and routes it to the right application. You need to tell Traefik to forward traffic for `plane.yourdomain.com` to Plane's internal proxy container. ### 6a — Find Plane's Docker Network SSH into your server and run: ``` bash sudo docker network ls ``` You'll see output like: NETWORK ID NAME DRIVER SCOPE 1ca43bdda6db bridge bridge local 7bebd2e6a992 sok0sgggc88kss0sos8k4w0s bridge local The network with a random-looking name (not `bridge`, `host`, or `none`) is Plane's Docker network. Note the **Network ID** (e.g. `7bebd2e6a992`). To confirm it's Plane's network, run: ``` bash sudo docker inspect YOUR_NETWORK_ID | grep -i "name\|container" ``` You should see container names like `proxy-...`, `api-...`, `web-...`, etc. That confirms it's the right network. Also note the **exact name of Plane's proxy container** from this output — it will look like `proxy-sok0sgggc88kss0sos8k4w0s`. You'll need this in the next step. ### 6b — Connect Traefik to Plane's Network Traefik runs inside Docker and by default can only reach containers on its own network. Run this command to connect it to Plane's network (replace `YOUR_NETWORK_ID` with the ID you found above): ``` bash sudo docker network connect YOUR_NETWORK_ID coolify-proxy ``` ### 6c — Create the Traefik Routing Rule Now create a dynamic configuration file that tells Traefik how to route traffic for your domain. Replace `plane.yourdomain.com` with your actual domain, and `proxy-sok0sgggc88kss0sos8k4w0s` with your actual proxy container name from Step 6a. ``` bash sudo tee /data/coolify/proxy/dynamic/plane.yaml << 'EOF' http: routers: plane-http: rule: "Host(`plane.yourdomain.com`)" entryPoints: - http middlewares: - redirect-to-https service: plane plane-https: rule: "Host(`plane.yourdomain.com`)" entryPoints: - https service: plane tls: certResolver: letsencrypt middlewares: redirect-to-https: redirectScheme: scheme: https permanent: true services: plane: loadBalancer: servers: - url: "http://proxy-sok0sgggc88kss0sos8k4w0s:80" EOF ``` > **What this does:** It creates two Traefik routers — one that catches HTTP traffic and redirects it to HTTPS, and one that handles HTTPS traffic with an automatically issued Let's Encrypt SSL certificate, forwarding everything to Plane's internal proxy container by name. ### 6d — Set Correct File Permissions and Reload Traefik Traefik runs as a non-root user (UID 9999). The config file needs to be owned by that user, otherwise Traefik silently ignores it: ``` bash sudo chown 9999:9999 /data/coolify/proxy/dynamic/plane.yaml sudo docker kill --signal=SIGHUP coolify-proxy ``` The `SIGHUP` signal tells Traefik to reload its configuration without restarting. ------------------------------------------------------------------------ ## Step 7 — Verify It's Working Open your browser and go to `https://plane.yourdomain.com`. You should see the Plane sign-up screen. Create your admin account and your first workspace. > If you see a **Bad Gateway** error, wait 30–60 seconds and refresh. Traefik may still be issuing the SSL certificate from Let's Encrypt. If the error persists, check the troubleshooting section below. ------------------------------------------------------------------------ ## Step 8 — Access the Instance Admin Panel Plane has a separate admin panel called **God Mode** for managing instance-level settings like authentication methods, email configuration, and sign-up restrictions. Access it at: https://plane.yourdomain.com/god-mode/ Log in with the same credentials you used to create your first account. From here you can: - Enable or disable public sign-ups - Configure SMTP for email notifications - Set up OAuth (Google, GitHub) - View instance health and telemetry settings ------------------------------------------------------------------------ ## Troubleshooting **Bad Gateway after setup** This usually means Traefik can't reach Plane's proxy container. The most common causes are: 1. The `plane.yaml` file has wrong permissions — re-run the `chown` command from Step 6d. 2. Traefik isn't connected to Plane's Docker network — re-run the `docker network connect` command from Step 6b. 3. The container name in `plane.yaml` is wrong — double-check it against the output of `sudo docker inspect YOUR_NETWORK_ID | grep Name`. **Migrator container keeps restarting** This is normal on the first run. The migrator is a one-time job — once it finishes applying database migrations, it exits. Coolify may show it as "Exited" which is the correct final state. **Coolify shows "Degraded (unhealthy)"** This is expected and can be ignored. Coolify can't perform health checks on manually managed Docker Compose stacks. As long as your containers are running and the site is accessible, everything is fine. **SSL certificate not issuing** Make sure your domain's A record is pointing to the correct server IP and has fully propagated. You can check propagation at [dnschecker.org](https://dnschecker.org/). Traefik will automatically retry certificate issuance — give it a few minutes. **Port 8090 already in use** Run `sudo ss -tlnp | grep 8090` to check. If it's taken, choose another free port (e.g. 8091), update `LISTEN_HTTP_PORT` in your environment variables, redeploy, and update the `published` port in the compose file's proxy service accordingly. ------------------------------------------------------------------------ ## Summary You now have a fully self-hosted Plane instance running on your own infrastructure at zero licensing cost. Here's what you set up: - A full Plane Community Edition stack with PostgreSQL, Redis, RabbitMQ, and MinIO storage - Coolify managing the Docker Compose deployment - Traefik handling HTTPS with automatic SSL from Let's Encrypt - A clean routing setup that doesn't interfere with other apps on the same server The Community Edition includes unlimited projects, unlimited users, kanban boards, timelines, cycles, modules, dashboards, pages, and a full REST API. For most small to medium teams migrating off Monday.com, it covers everything you need. ------------------------------------------------------------------------ *This guide was written by [Batin Studio](/), a Shopify CRO agency that designs, builds and tests changes to Shopify stores. Questions about this setup? Email hello@batinstudio.com.* --- ### 5 Best Shopify Apps That Automatically Optimize Images on Upload (2025) URL: https://batinstudio.com/blog/5-best-shopify-apps-that-automatically-optimize-images-on-upload-2025 · Shakhawat Hossen · 2025-12-23 · Speed & images Running a Shopify store involves a million tiny tasks. One of the most tedious? Manually resizing and compressing product photos before you upload them. If you forget to do it even once, you risk bloating your site code, slowing down mobile loading speeds, and hurting your Google rankings. The solution is **automation**. You need a plugin that acts as a "gatekeeper," automatically catching every new image you upload, compressing it instantly, and replacing it without you lifting a finger. We tested the top apps on the Shopify App Store to find the ones that truly deliver on the "set and forget" promise. Here are the top 5 plugins for automatic image optimization in 2025. ## 1. Auto Media Optimizer **Best For:** Merchants who want complete, hands-free automation. If you value your time, **Auto Media Optimizer** is the ultimate efficiency tool. While other apps often require you to log in, select images, and click "Optimize," this app is built on a "Zero-Touch" philosophy. It runs entirely in the background, acting as an invisible quality control team for your store. **How the Automation Works:** The moment you upload a new product image to Shopify, the app wakes up. It instantly detects the new file, optimizes it on a remote cloud server to reduce file size without losing quality, and seamlessly replaces the original. This happens automatically for every single upload, 24/7. You can literally install it and never open the dashboard again, knowing your site speed is being protected while you sleep. ### Pros - **100% Background Automation:** No manual clicking required. It monitors your store and optimizes new uploads instantly. - **Massive Time Saver:** Eliminates the need for staff to manually resize or compress images before uploading. - **True "Unlimited" Plan:** Unlike competitors who charge per image credit, the Pro plan (\$9.99) offers unlimited optimization. ### Cons - **Specialized Focus:** It is purely an image tool; it does not handle other SEO tasks like JSON-LD or Meta Tags. - **Newer to Market:** Has fewer reviews than legacy apps that have been around for 5+ years. **App link:** [https://apps.shopify.com/auto-media-optimizer](https://apps.shopify.com/auto-media-optimizer) ## 2. TinyIMG **Best For:** Stores that need a full SEO suite. TinyIMG is one of the most well-known names in the space. It is a robust tool that does more than just images; it also handles JSON-LD structured data, broken link redirection, and meta tag optimization. ### Pros - **All-in-One Suite:** Handles image compression, broken link redirects, and metadata in one dashboard. - **Trusted Reputation:** Used by over 100,000 merchants with a proven track record. - **Visual Audit:** Provides a nice "Before and After" preview of quality reduction. ### Cons - **Credit-Based Pricing:** You pay per image. If you have a large catalog or bulk upload frequently, it gets expensive fast. - **Feature Bloat:** The dashboard can be overwhelming if you are only looking for image compression. **App link:** [https://apps.shopify.com/smart-image-optimizer](https://apps.shopify.com/smart-image-optimizer) ## 3. Crush.pics **Best For:** SEO file renaming. Crush.pics is famous for its renaming capabilities. Beyond just file size, it helps you rename your image files (e.g., changing `IMG_1023.jpg` to `leather-jacket-black.jpg`) automatically, which helps Google Image Search understand your content. ### Pros - **SEO Renaming:** The best logic for automatically renaming file names for SEO keywords. - **Flexible Compression:** Allows you to choose between "Balanced," "Lossless," and "Lossy" modes. - **30-Day Backup:** Keeps your original images for 30 days in case you want to revert changes. ### Cons - **Manual Free Plan:** The free tier requires you to manually click "Compress" on images; automation is paid-only. - **Complex Setup:** Configuring the renaming rules can be slightly technical for beginners. **App link:** [https://apps.shopify.com/crush-pics](https://apps.shopify.com/crush-pics) ## 4. Avada SEO **Best For:** High-volume stores needing simple speed boosts. Avada is a massive suite of tools. Their image optimizer is just one part of a very large ecosystem. It’s effective and fast, offering high-speed compression servers that can handle thousands of SKUs quickly. ### Pros - **Page Pre-loading:** Includes a "smart speed" feature that pre-loads pages before users click them. - **Excellent Support:** Known for having very fast, 24/7 chat support. - **Good Free Tier:** Useful for very small shops just starting out. ### Cons - **Upsell Heavy:** The dashboard is often cluttered with ads for their other apps (Email, Reviews, etc.). - **Frontend Scripts:** Some of the "Speed Booster" features add scripts to your theme, which can ironically slow down render times if not configured correctly. **App link:** [https://apps.shopify.com/avada-seo-suite](https://apps.shopify.com/avada-seo-suite) ## 5. Booster SEO & Image Optimizer **Best For:** Complete beginners. Booster takes a simplified approach. It doesn't offer as many granular controls as Crush.pics or Auto Media Optimizer, but it is incredibly easy to install. It focuses heavily on the "SEO" aspect, ensuring your Alt Text is automatically populated based on product templates. ### Pros - **Zero Configuration:** True "One-Click" install for non-technical users. - **Alt-Text Focus:** Automatically fixes missing Alt Text for accessibility and SEO. - **Broken Link Fixer:** Monitors your site for 404 errors automatically. ### Cons - **Lack of Control:** You cannot fine-tune the compression levels; you just have to trust their settings. - **Expensive Upgrades:** The "Free Forever" plan is very limited; the useful features are locked behind a \$39/mo plan. **App link:** [https://apps.shopify.com/booster-apps-seo-optimize](https://apps.shopify.com/booster-apps-seo-optimizer) ## \ Which One Should You Choose? If you are looking for a heavy-duty SEO suite and have the budget, **TinyIMG** is a safe bet. However, if you want a modern, lightweight tool that handles unlimited images without breaking the bank, **Auto Media Optimizer** is the breakout star of 2025. It offers the same "Autopilot" compression technology as the big players but focuses entirely on speed and ease of use. You can [**try Auto Media Optimizer for free here**](https://apps.shopify.com/auto-media-optimizer) to see the difference in your site speed immediately. --- ### How to enable automatic image compression on Shopify URL: https://batinstudio.com/blog/how-to-enable-automatic-image-compression-on-shopify · Shakhawat Hossen · 2025-12-23 · Speed & images If you have ever run a Google PageSpeed test on your Shopify store, you have likely seen the warning: *"Serve images in next-gen formats"* or *"Efficiently encode images."* High-resolution product photography is essential for selling, but it is also the number one reason Shopify stores load slowly. A slow store means lower rankings on Google and, more importantly, lost sales from mobile customers who won't wait for a page to load. The solution is **image compression**. But manually resizing thousands of product photos is impossible for a busy merchant. In this guide, we will look at how to enable **automatic** image compression so every new product you upload is optimized instantly in the background. ## Why You Cannot Rely on Shopify's Default Settings Many merchants assume Shopify handles this automatically. While Shopify does generate different image sizes for thumbnails, it does not always aggressively compress the file size for bandwidth optimization. Without a dedicated compression engine, you are often serving files that are 2x or 3x larger than they need to be, without any noticeable difference in visual quality. To fix this, you need a "set and forget" automation tool. ## Step 1: Choose an Automation App To automate this workflow, you need an app that hooks into Shopify's "file upload" events. There are several options on the market, but for this tutorial, we will use [**Auto Media Optimizer**](https://apps.shopify.com/auto-media-optimizer "Shopify App: Auto Media Optimizer") because it focuses specifically on background automation without complex configurations.\ \ **Install link:** [https://apps.shopify.com/auto-media-optimizer](https://apps.shopify.com/auto-media-optimizer) ## Step 2: Install and Sync Your Library Once you have installed the app from the Shopify App Store, the first step is usually a "Sync" or "Scan." The app will look through your *Products*, *Collections*, and *Files* API to build a list of unoptimized assets. Do not worry—this doesn't change anything on your live site yet; it just calculates how much space you can save. ## Step 3: Enable "Auto-Optimize" Mode This is the most critical step for automation. Look for the setting labeled **"Automatic Optimization"** or **"Autopilot."** When you turn this on, the app creates a background listener. Here is what happens next: - You upload a new product photo to Shopify. - The app detects the new image instantly. - It compresses the image according to your settings (we recommend "75-80" for the best mix of quality and speed). - The optimized version replaces the heavy original automatically. You no longer need to use Photoshop or online compressors before uploading. You just upload, and the app handles the rest.\ ## Step 4: Bulk Optimize Existing Images Enabling automation handles *future* images, but what about the thousands of images already on your store? Navigate to the **Dashboard** and click **"Optimize All"** or **"Start Bulk Task."** This process runs in the cloud, so you can close the window and turn off your computer. The app will work through your catalog image by image. ***Note:** We always recommend backing up your theme or ensuring the app has a "Restore" function before running a bulk action, just in case you prefer the original version.* ## Step 5: Check Your New Speed Score After the optimization is complete (it might take a few hours depending on your store size), head back to Google PageSpeed Insights. You should see a significant drop in "Total Page Size" and a faster "Largest Contentful Paint (LCP)" score. Faster loading times directly correlate to better ad performance and higher conversion rates. ## Conclusion Speed is a competitive advantage in 2025. By automating your image compression, you remove a tedious manual task from your to-do list and ensure your store is always fast, no matter how many products you add. Ready to speed up your store? [**Try Auto Media Optimizer for free on the Shopify App Store.**](https://apps.shopify.com/auto-media-optimizer) --- ### The "Silo Effect": Why Great Product Ideas Fail in Execution (And How to Fix It) URL: https://batinstudio.com/blog/the-silo-effect-why-great-product-ideas-fail-in-execution-and-how-to-fix-it · Shakhawat Hossen · 2025-12-09 · Notes **Category:** Startup Strategy / Product Management\ **Read Time:** 6 Minutes ------------------------------------------------------------------------ ## The Gap Between "Vision" and "Version 1.0" We see it all the time in the startup world. A founder has a brilliant concept. They hire a talented freelance designer to mock it up. It looks stunning—Dribbble-worthy. Then, they hand those files to a developer. Three months later, the product launches. But it feels… off. The animations aren't smooth. The mobile responsiveness is clunky. The features are there, but the *magic* isn't. Why does this happen? It’s not because the designer was bad, or the developer was lazy. It’s because of **The Silo Effect**. When design and development happen in separate rooms (or separate freelance contracts), the product suffers. ## The "Personal Product Team" Approach The most successful digital products—from simple **premium websites** to complex **SaaS platforms**—are not built on an assembly line. They are built by a unified brain. If you are trying to scale your business, you need to stop thinking in terms of "tasks" (e.g., *I need a logo, then I need a code snippet*) and start thinking in terms of "product ecosystem." Here is how you can apply this mindset to your own business to ensure your next launch is a success. ### 1. Design for Scalability, Not Just Aesthetics A pretty interface is useless if it breaks when you add your 1,000th user. When we approach a project, we don’t just paint pixels. We look at the architecture. - *Is this button placement sustainable if we add three new features next year?* - *Does this color palette support dark mode accessibility?* True product design anticipates the code before a single line is written. If you are browsing through [our portfolio at Batin Studio](/), notice how the visuals aren't just "art"—they are functional systems meant to grow with the company. ### 2. Eliminate the "Handoff" Friction In the traditional model, a designer finishes a file and "hands it off" to a developer. This is where 20% of the quality is usually lost in translation. The fix? **Parallel Development.** Your design and development resources need to be in constant communication. The developer should be vetting the designs for feasibility on day one. The designer should be QA-ing the code on day thirty. This is why many founders are moving away from managing five different freelancers and moving toward the "Personal Team" model. It consolidates accountability. You can see examples of how this integrated workflow results in cleaner **apps and branding** on our main site. ### 3. Brand Consistency is a Technical Requirement Your brand isn't just your logo; it's the speed of your website. It's the smoothness of your page transitions. If your marketing claims you are "Premium" and "High-Tech," but your website loads in 4 seconds because of poorly optimized code, you have broken your brand promise. To attract high-ticket clients, your backend performance must match your frontend beauty. ## The Takeaway If you are struggling to get your digital presence to match the quality of your actual service, stop hiring for "tasks." Start looking for partners who understand the whole picture. Whether you build an in-house team or partner with a dedicated studio like ours, the goal is the same: **One vision, executed flawlessly.** *Do you want to see what a fully integrated design & dev team can do for your specific niche? Feel free to explore our [case studies here](/) to see the difference cohesion makes.*