SafeSale · Blog

Sale badges without editing your Shopify theme code

Why discount apps that inject theme code break carts and layouts, how to remove leftover app code from your Shopify theme, and how app extensions avoid it.

If you are searching “shopify app broke my theme” or “remove discount app code from shopify theme”, you have already met the old way sale apps got badges and crossed-out prices onto a storefront: by editing the theme. This article explains why injected theme code breaks carts and layouts, how to clean it out of a theme by hand, and how a sale badge without editing your theme works using Shopify’s theme app extensions, which is how SafeSale’s badge and countdown are built.

The problem: the app is gone, its code is not

On Discount Ninja’s one- and two-star review page a July 7, 2020 review asks why, after uninstalling, the app “leaves behind all its code in my theme”, and lists the snippet files by name. A June 24, 2020 review on the same page describes a code installation after which “My checkout button became disabled”; the developer’s reply attributes it to another app, which is itself a reminder that two apps editing one theme is how these conflicts start. On Bold Discounts’ review page an August 18, 2020 review says that even after deleting the app it “completely changed the layout on my collections pages and the way my prices are shown”. Please read the pages and the replies rather than relying on these fragments.

Two separate failures are tangled up here. The first is breakage while the app is installed: injected scripts and Liquid that interfere with the cart, the checkout button or the price markup. The second is breakage after uninstall: files and references left behind that either keep rendering, render errors, or block a theme update.

Why it happens: traditional theme integration edits your files

Shopify’s own documentation on migrating apps to theme app extensions describes the older approach plainly: apps “will traditionally modify theme code to inject assets, extract data, and extend theme functionality”, and “uninstalling apps often leaves the code edits, or ghost code, behind in the theme, which can cause quality and performance issues and takes merchants off their theme upgrade paths.” The same page names the two mechanisms involved: writing files into the theme through the Asset API and injecting JavaScript through script tags.

Three things follow from that design:

  • The app’s code runs on every page, next to every other app’s code. A script that rewrites price elements or hooks the add-to-cart button is one selector change away from disabling checkout when the theme, or another app, updates.
  • Uninstall cannot clean up. Shopify revokes an app’s access token when it is uninstalled (access tokens), so an app that edited your theme can no longer edit it back. The Help Center page on uninstalling apps warns that some apps add code to your theme that is not removed automatically and may need additional steps.
  • The theme is now a fork. Once an app has written into layout or section files, updating to a new theme version means redoing or losing those edits, which is what “takes merchants off their theme upgrade paths” means in practice.

There is a related misunderstanding about what a crossed-out price is. Shopify’s sale pricing guide explains that themes show a strike-through when a variant’s compare-at price is higher than its price, and that automatic or code discounts are shown at checkout instead; whether and where sale prices display “depends on your theme”. An app that promises a strike-through for a checkout discount has to fake it in the theme, which is exactly the code that gets left behind.

The manual fix: remove leftover app code from a theme

  1. Duplicate the live theme (Online Store → Themes → ⋯ → Duplicate) and work on the copy. If you have a backup from before the app was installed and have not changed the theme since, publish that instead and stop here.
  2. Search for the app’s footprint. Open the code editor and look for the app’s name or prefix in layout/, sections/, snippets/ and assets/. Leftover snippets are usually obvious from their file names, as in the review above.
  3. Remove references before files. Deleting a snippet that is still rendered from theme.liquid or a product section produces a Liquid error on every page. Remove the render/include tags and script tags first, then delete the files.
  4. Check Theme settings → App embeds for an embed that belongs to the app, and turn it off.
  5. Preview, then publish. Test a product page, a collection page and a full add-to-cart to checkout on the duplicate before you make it live. If prices are also wrong, fix those separately; see sale prices stuck after uninstalling.

How SafeSale shows badges and countdowns without touching theme files

Shopify’s recommended mechanism is the theme app extension: the app ships blocks that appear in the theme editor, merchants add and position them visually, and, per Shopify’s documentation, merchants “won’t need to manually edit their theme code”. Shopify’s changelog entry announcing the feature adds that uninstalls are cleaner, with ghost code automatically removed. SafeSale is built on exactly this, and this is how it works today:

  • Two extension pieces, added from the theme editor. A Sale badge app embed, enabled under Theme settings → App embeds, shows a store-wide sale badge; a Sale countdown app block can be dropped into a product template section. Both are configured in the editor: text, colours, position.
  • Data flows through metafields, not code. When a sale starts, SafeSale writes an app-owned metafield on the shop (for the badge) and on each product in the sale (for the countdown, with the end time). When the sale ends or is restored, those metafields are cleared. The Liquid in the blocks reads the metafields and renders nothing when they are empty.
  • No theme permissions at all. SafeSale requests two access scopes, write_products and write_discounts. It cannot read or write theme files, so “the app changed my theme” is not a failure mode it can have.
  • The strike-through is the theme’s own. In price-rewrite mode SafeSale sets the variant’s compare-at to the original price and the price to the sale price, and your theme renders the crossed-out price exactly as it would if you had typed the values in the admin. Nothing in the extension rewrites price markup. In the default automatic-discount mode there is no storefront strike-through, and SafeSale does not fake one; the discount shows in the cart and checkout as Shopify documents.

Limits worth knowing: app blocks only work in published themes that support them, as Shopify’s migration guide notes, so a very old theme may only be able to use the app embed. And the badge is store-wide by design; per-product “SALE” labels are the theme’s job, driven by the compare-at price. The bulk discount app checklist includes the theme questions to ask any vendor before installing.

Next step

SafeSale is not yet publicly listed on the Shopify App Store. The landing page shows the badge and countdown on a demo storefront. See SafeSale’s theme-editor badge and countdown.

Frequently asked questions

How do I remove discount app code from my Shopify theme?

Duplicate the theme first. Then, in the code editor, search the layout, sections, snippets and assets for the app's prefix, remove the render or include tags that reference its snippets, delete the snippets and assets themselves, and check Theme settings for a leftover app embed. Preview the duplicate before publishing it. If the theme has a pre-install backup, publishing that is faster.

Can a Shopify app add a sale badge without editing my theme?

Yes. Theme app extensions let an app provide app blocks and app embeds that you add and position from the theme editor. Shopify documents that merchants do not need to edit theme code for them, and when the app is uninstalled its blocks stop rendering instead of leaving code behind.

Does SafeSale write anything to my theme files?

No. SafeSale's storefront pieces are a theme app extension: a store-wide sale badge app embed and a per-product countdown app block. They read metafields the app owns. SafeSale requests only the write_products and write_discounts access scopes, so it has no permission to edit themes at all.

Why did my strike-through price disappear when I switched to an automatic discount?

Because a crossed-out price on product and collection pages is the theme rendering a compare-at price that is higher than the price. Automatic and code discounts are applied in the cart and checkout instead, so Shopify's documentation notes that showing them on the storefront needs the theme or an app to do it. Only a price rewrite, which sets the compare-at field, produces the native strike-through.