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.
- From your Shopify admin, go to Products and click the product you want to mark down.
- In the Pricing section, find the Compare at price field and enter the original price.
- In the Price field, enter the new, lower price.
- 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.
- From your Shopify admin, go to Products.
- Use the checkboxes to select every product you want to put on sale.
- Click Edit products (sometimes labeled Bulk edit) at the top of the list.
- If the Compare-at price column isn't already visible, click Columns and add it.
- 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.
- 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.
- From your Shopify admin, go to Products and click Export. Choose the products you want and download the CSV.
- 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.
- 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.8next 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. - Save the file as a CSV.
- 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 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.