Taming Shopify Product URLs: How to Banish '?variant=' for Single-Option Products

Hey fellow store owners! Let's talk about something that might seem small but can make a big difference for your Shopify store's user experience and even SEO: those pesky ?variant= parameters showing up in your product URLs, even when a product only has a single, default variant.

I recently saw a great discussion pop up in the Shopify community, initiated by @thewebsitewebmaster, who was grappling with this exact issue. They were using the Horizon theme and noticed that even for products with only a "Default Title" variant, the URL would still append ?variant=123456789. This isn't ideal, right? It makes URLs look a bit messy and can be confusing, especially when there's no actual variant to select.

The Problem: Unnecessary Variant IDs in URLs

Shopify, by default, often includes the variant ID in the URL for product pages. This is super helpful when you have multiple options (like size or color) because it ensures the correct variant is loaded and displayed when someone shares a direct link. However, for products that don't have any real variants – just that standard "Default Title" option – having ?variant= in the URL is redundant.

It's like carrying an umbrella on a perfectly sunny day. While it doesn't break anything, it's just extra baggage. For store owners, this means slightly less clean URLs, and for some, it might even raise minor SEO questions (though Google is generally smart enough to handle URL parameters). The core desire, as highlighted by our community member, is to keep those URLs pristine when they should be.

The original post included a snippet of their product-variant.js from the Horizon theme, showing how the variant ID was being handled:

const url = new URL(window.location.href);
const variantId = selectedOption.dataset.variantId || null;

if (isOnProductPage) {
  if (variantId) {
    url.searchParams.set('variant', variantId);
  } else {
    url.searchParams.delete('variant');
  }
}

This code, as written, would always add the variant ID if one existed, even if it belonged to the "Default Title" variant.

Solution 1: The Quick Liquid & JavaScript Clean-Up (Client-Side)

One elegant solution, shared by Moeed, involves a small Liquid-gated JavaScript snippet. This approach is fantastic because it's non-invasive and easy to add directly to your product template or a custom Liquid block. It works by checking if a product only has the "Default Title" variant using Liquid's built-in product.has_only_default_variant property. If it does, a small JavaScript piece then strips the ?variant= parameter from the URL after the page loads.

How to Implement Moeed's Solution:

  1. Navigate to your Theme Code: From your Shopify admin, go to Online Store > Themes.
  2. Edit Code: Find your current theme, click Actions > Edit code.
  3. Find Product Template/Section: Look for files like sections/main-product.liquid, templates/product.liquid, or a custom Liquid block you might be using on your product page.
  4. Add the Script: Paste the following code snippet within your chosen file. A good spot is typically near the end of the file or within the main product section, ensuring it runs after the product information has loaded.
{% if product.has_only_default_variant %}
  
{% endif %}

This script is smart. It only runs if product.has_only_default_variant is true, and it uses history.replaceState to update the URL without reloading the page. Just a heads-up from Moeed: if your collection product cards are already linking with ?variant= baked in, this script cleans the URL on the product page itself, but you'd need to adjust those collection card links separately if you want that pre-click cleanliness.

Solution 2: Deeper Dive into product-variant.js (Theme JS Modification)

For those comfortable digging into theme JavaScript, especially if you're using a theme like Horizon (as the original poster was), a more integrated solution involves modifying the theme's core variant-handling logic. This approach, outlined by devcoders and rajweb, prevents the ?variant= parameter from being added in the first place when the "Default Title" variant is selected.

How to Implement the Theme JS Modification:

  1. Backup Your Theme: Seriously, this is crucial. Before making any JavaScript changes, duplicate your theme so you have a rollback option.
  2. Locate product-variant.js: In your theme code editor (Online Store > Themes > Actions > Edit code), navigate to your JavaScript assets, typically in the assets/ folder. You're looking for product-variant.js or a similar file that handles variant changes.
  3. Find the variantChanged() Method: Inside this file, search for the variantChanged(event) method. This is the function responsible for updating the product display and URL when a variant is selected.
  4. Modify the URL Update Logic: Within the variantChanged() method, you'll find a section that handles setting or deleting the variant URL parameter. You need to introduce a check to see if the selected variant is the "Default Title" before adding the parameter.

Here's how devcoders suggested updating the relevant part of the variantChanged() method. You'll be replacing the original URL update logic with this more robust version:

const url = new URL(window.location.href);
const variantId = selectedOption.dataset.variantId || null;

const opti
  selectedOption.value ||
  selectedOption.getAttribute('value') ||
  selectedOption.textContent ||
  ''
)
.trim()
.toLowerCase();

const isDefaultTitleVariant = opti 'default title';

if (isOnProductPage) {
  if (variantId && !isDefaultTitleVariant) {
    url.searchParams.set('variant', variantId);
  } else {
    url.searchParams.delete('variant');
  }
}

This snippet first gets the optionValue and checks if it's 'default title' (case-insensitively). Then, it only sets the variant parameter if a variantId exists AND it's NOT the default title variant. Otherwise, it makes sure to delete the parameter. Rajat's suggestion also included adding data-has-only-default-variant="{{ product.has_only_default_variant }}" to the variant picker element, which could provide another way to check, but the optionValue check directly within the JS is very effective.

The result of this modification, as devcoders pointed out, is exactly what we're looking for:

  • Single default variant: /products/product-handle
  • Real selected variant: /products/product-handle?variant=123456789

Which Solution is Right for You?

Both approaches tackle the problem effectively. Moeed's Liquid-gated script is a fantastic, lightweight option if you want a quick fix without diving deep into your theme's JavaScript files. It's great for themes where the product-variant.js might be complex or if you prefer less invasive changes.

The product-variant.js modification, on the other hand, offers a more integrated and "source-level" fix. If you're using a theme like Horizon, this is often the cleaner, more robust way to handle it, as it modifies the logic that generates the URL parameter in the first place. Just remember to always back up your theme before making direct edits to JavaScript files!

It's awesome to see the community come together to solve these kinds of practical challenges. Whether you're a seasoned Shopify veteran or just getting started on Shopify, these insights from fellow store owners and developers are invaluable. Give these solutions a try, and let's keep those URLs clean and user-friendly!

Share:

Start with the tools

Explore migration tools

See options, compare methods, and pick the path that fits your store.

Explore migration tools