Skip to content
best-practices·04.10.2026·7 min read

Personalized Products and Packaging Fees in Shopify

How I modeled printed cups with tiered prices and a logo upload in Shopify, and the options I weighed for passing a per-item packaging licence fee through to customers — with the pitfalls I hit.

Product configurator with size and quantity tiles and a logo upload, next to a cart that separates a regulatory packaging fee line

Two requests landed on my desk within days of each other from a small Shopify merchant selling disposable drinkware and packaging to businesses. First: "we want customers to order cups printed with their own logo, with different prices depending on size and quantity." Second: "every article carries a packaging licence fee, how do we show that cleanly?" Different problems, same underlying question — what does Shopify's data model actually let you express, and where do you stop fighting it? This post is how I approached both, what I verified, and what is still open.

Personalized Cups: Model Prices as Variants

The tempting version is a base product plus a quantity field plus an app that computes a discounted price. I avoided it. Tiered unit prices are a pricing table, not a discount rule, and the supplier's price list already existed in exactly that shape: size × quantity → price per 1,000.

So the product is one product with variants:

  • Option 1: size (four cup sizes)
  • Option 2: quantity (1,000 to 5,000 units — the client wanted to start capped at 5,000; anything above goes through a contact path)
  • Variant price = total price, i.e. table price × quantity ÷ 1,000

That gave 20 variants, each with its own SKU, no inventory tracking, and "continue selling when out of stock" on. The storefront shows the per-unit price as derived information on each quantity tile. Shopify caps a product at three options, so I left the third slot free: the client mentioned further attributes might follow, and a fourth would only be possible as a non-priced property.

Two pitfalls worth naming:

Rounding. The price list is quoted per 1,000 and rounded. Multiplying a rounded table value by three can differ by one cent from the supplier's own total. I asked for the exact totals before import instead of silently picking a side. Cheap to ask, awkward to explain on an invoice.

Existing discount apps fight tiers. The store had a "buy more, save more" volume-discount block installed. On a product whose price is already the tier price, it has to be switched off for that template, or you stack two pricing systems.

I made it a new product rather than extending the existing cups. The existing ones were separate products per size priced per pack unit; sizes didn't map one to one, and merging catalogs would have meant rewriting working SKUs that an ERP connector depends on.

The Logo Upload: Properties, Not Variants

The logo is not a price dimension, so it does not belong in a variant. Shopify's mechanism is a line item property — extra key/value data attached to the cart line, visible in the order. The store already ran a product-options app that supports file upload, so I did not build my own uploader:

  • required file field, extensions limited to SVG, PDF, PNG (JPG was added later after a client request)
  • optional free-text field for print notes
  • required checkbox: custom-made goods are excluded from the right of withdrawal
  • option set assigned only to the new product

The uploaded file ends up as a URL stored in the Logo property. A detail that cost me a minute: the app rejects commas, colons and quotation marks in option values, so the legal checkbox text had to use a dash.

The configurator is a theme template

On the storefront I did not want a stock variant picker. I built a dedicated product template with its own section:

  • size and quantity as tiles, each quantity tile showing total and per-unit price
  • unavailable combinations disabled, selected variant reflected in the URL
  • steps in the order a buyer thinks: size, quantity, logo, then the total directly above the add-to-cart button
  • the quantity input removed — quantity is part of the variant, so a second quantity stepper would multiply the price

Once a logo is chosen, a small preview renders it on the cup photo, with an explicit "size and position of the print are not binding" note. PDFs get no preview, just a message that the logo is checked before printing. The preview was only verified on desktop with an SVG test file; I'd not claim more.

Theme work: where I got burned

Two lessons that apply to any Shopify theme job:

  1. A template only exists for products if it is in the published theme. The admin's template dropdown lists the live theme's templates. I built in an unpublished copy, so the product could not be assigned to it, and add-to-cart on the draft failed with "cannot find variant". Publishing a whole copied theme to fix that would overwrite anything changed in the live theme since the copy. My recommendation was to add the two new files to the live theme and touch nothing else.
  2. A preview link is not a theme link. ?view=<template> only selects a template in whichever theme is currently rendered. A teammate opening the link saw the live theme and the default product page. Preview needs the theme ID (preview_theme_id) or the admin-initiated preview.

The Packaging Fee: Options Compared

The second request started from a spreadsheet: per article, a licence fee computed as weight × rate per material, per packaging unit. In the file I analysed, the per-unit fees ranged from a few cents to roughly twenty euros.

I laid out five ways to put this into Shopify:

OptionIdeaVerdict
ABake the fee into the price; show "incl. X packaging licence" from a variant metafieldSimplest, works with express checkout and B2B catalogs, no app. No separate invoice line; discounts also reduce the fee.
BCart Transform Function expanding each item into item + fee lineFee is its own line in checkout, order and invoice. Needs a custom app and ERP import testing; direct price override (lineUpdate) needs Plus per Shopify's docs.
COff-the-shelf fee appFast, but recurring cost and vendor dependency; must verify metafield-driven amounts.
DSeparate fee product, quantity adjusted by theme JavaScriptFragile: customers can delete the line, express checkout bypasses the script. Not recommended.
EFold the fee into shipping via carrier serviceOpaque to customers. Not recommended.

My recommendation depended on one question I had to ask the client: does the shop sell to consumers, businesses, or both? Consumer prices must be total prices, which makes A the clean answer. If business customers need the fee as its own invoice line, B is the proper build.

Either way the spreadsheet becomes the single source of truth: fee per SKU imported into a variant metafield by CSV.

What the data review turned up

Before any import, I read the sheet instead of trusting it:

  • a few articles had no weight and would have received a 0 fee
  • some lids named as one material were recorded under another
  • a handful of weights per piece were implausible (well under a gram for a tub)
  • the weights looked like gross per pack, probably including the outer carton — which would overcharge if the carton is not licensed packaging. That was an assumption I flagged, not a finding.

On the shop itself the fee already existed in a different form: scheduled Shopify Flow workflows per material compute weight × rate into the existing fee. Checking one cup, the arithmetic matched the admin figure exactly (11.2 kg × 1.27 €/kg = 14.22 € per 1,000). The consequence for the personalized product: the draft deliberately has no fee yet, because without weight and material per variant Flow cannot compute it. I wrote that down as a go-live blocker rather than letting it hide.

Open Questions I Left With the Client

Honest list, because most of the risk lives here:

  • Does the fee apply to every product, or only licensed packaging types?
  • Is the rate per kg final, and which material is each variant?
  • Are weights net of the outer carton?
  • Does the ERP connector overwrite variant prices per SKU? I could not know before a test order.

Takeaways

  • Model price tiers as variants when the price list is a table. Use properties for data that does not change the price.
  • Reuse the options app that is already installed; build only the storefront experience.
  • Never assume a theme template is assignable until it exists in the live theme.
  • For a regulatory fee, decide first whether it must be an invoice line. That one answer picks the architecture.
  • Run the spreadsheet through a data review before it becomes prices.

If you are modeling configurable products or regulatory surcharges in Shopify, get in touch.

Enjoyed this?

Get new posts as they land.

Subscribe via RSS

Keep reading