Shopify cart price fields — what line_price and final_line_price actually mean
Measured on a live cart carrying a cart-level discount. The docs say the two fields are aliases. On that cart they differ by $120.
If you are reading /cart.js and deciding what a line costs, there are three price fields and
they do not mean the same thing. Shopify’s documentation carries a deprecation note saying
line_price is an alias for final_line_price. On a cart with a cart-level discount, it is
not.
The measurement
A live cart on a development store, one line item, one cart-level 20% discount applied:
{
"original_line_price": 60000,
"line_price": 48000,
"final_line_price": 60000,
"line_level_discount_allocations": [],
"total_price": 52792,
"items_subtotal_price": 65990
}
line_price and final_line_price differ by 12,000 cents. If they were aliases they could
not.
What each field is actually reporting
| Field | Reflects |
|---|---|
original_line_price |
before any discount |
line_price |
after cart-level discounts |
final_line_price |
after line-level discounts only |
cart.total_price |
after all discounts |
That explains the numbers. A cart-level discount moves line_price and leaves final_line_price
alone, because no line-level discount was applied. line_level_discount_allocations is empty
for the same reason: the allocation is not on the line.
Summing line_price across lines reproduces cart.total_price exactly.
Why it matters
If you are gating on a cart total, read cart.total_price. It is one documented field, after
everything, and it does not change meaning depending on which kind of discount a merchant happens
to be running. Summing line fields yourself means picking which discounts to honour, and getting
it wrong in a way that only shows up when a merchant runs a promotion you did not anticipate.
If you are checking whether one specific line is free, say a gift that must not be charged
for, neither field alone is safe. The two disagree and each captures a different level.
Taking min(line_price, final_line_price) can only understate the discount, which fails in the
safe direction: you might conclude a free line is not free and act conservatively, but you will
never conclude a charged line is free.
The general point
The deprecation note is not wrong so much as incomplete. The fields converge on a cart with only line-level discounts, which is the common case and presumably where the alias claim came from. They diverge as soon as a cart-level discount exists.
Do not reason about these fields from the documentation. Put a discount on a real cart, fetch
/cart.js, and read what comes back.
Measured 2026-09-09 on a Shopify development store, /cart.js, one line item, one active
cart-level percentage discount. Re-check before relying on it — this is a note about observed
behaviour on one date, not a specification.
This came out of building Giftline, a Shopify app I make, which has to prove a gift line is free before it will leave it in a cart. Shopify forbids an app adding a charge to a buyer’s cart, so reading the wrong field here breaks a platform rule before it costs anyone money.