PriceProof

BFCM price, margin and storefront checks

A manual worksheet for checking variant price restoration, contribution before and after a discount, and offer or policy mismatches across a Shopify storefront.

Use this guide with your own export, spreadsheet and storefront. It does not change prices, determine duty or tax, or decide whether a promotion complies with law. Community posts below explain why these checks exist; they are not legal authorities or independent verification of another store's current condition.

1. Price changes, restoration and prior-price display

Run all six checks for every variant in the campaign. A product-level success message is not enough.

CheckWhat to doEvidence to keep
1. Snapshot variant identityBefore the sale, export every included variant. Use the variant GID as the identity key, not SKU alone. Record product handle, SKU, variant GID, price, compare-at price, market, currency and capture time.Dated pre-sale snapshot. If a variant was deleted and recreated, mark a conflict and review it instead of restoring onto a matching SKU.
2. Separate four outcomesGive every intended variant exactly one outcome: applied, skipped or failed. Keep intended as the full input set. Count each group and list the reason for every skip or failure.intended = applied + skipped + failed. Treat a finished job with unresolved rows as unfinished work, not a clean restore.
3. Read back after the endAfter the scheduled end, read every intended variant again, including skipped and failed rows. Compare price and compare-at price with the pre-sale snapshot and the expected exception list.End time with timezone, read-back time, full result export and unresolved variant GIDs. Check leftover sale badges as well as prices.
4. Detect manual and ERP collisionsImmediately before restoring, compare the live value with both the original snapshot and the expected sale value. If another process changed it, stop that row for review. Do not blindly overwrite a newer manual or ERP price.Current value, expected value, conflict reason, owner and resolution. For CSV restores, review overwrite settings, empty cells versus omitted columns, and option columns.
5. Separate compare-at from sales historyTreat compare-at as a storefront field, not proof of what customers were charged. Keep observed selling prices and their timestamps in a separate record. Note missing history instead of filling it with compare-at.Price-history source, observation period, market, currency and gaps. Do not infer a prior selling price from RRP or a newly raised compare-at value.
6. Check each market separatelyRecord the market and currency for each price presentation. Check the rule, exceptions and display practice that apply there. Do not apply an EU, UK, Australian or Canadian benchmark as if it were one shared rule.Market, rule source checked, check date, reviewer and open questions. Ask a qualified adviser about application to your promotion where needed.

Restore record example

This is a fictional worksheet row, not a report from a live store.

Variant GIDMarketIntended priceExpected restored priceRead-back priceOutcomeNext action
gid://shopify/ProductVariant/41000000000001Germany / EUR26.0040.0040.00appliedNone
gid://shopify/ProductVariant/41000000000002Germany / EUR26.0040.0031.00failedERP changed the row; review before writing

The identity and read-back advice follows 673303 post #2, which says that "Job finished" and "every intended price verified" are different outcomes. Post #7 covers CSV import traps and separates compare-at from price history.

For observed restoration failures, see 695140 post #16 on prices and sale badges left behind, and post #30 on variants missed by a parent-product revert. Post #27 is a developer's view of EU prior-price display; use it as a prompt for a separate market check, not as a legal opinion.

2. Landed-cost and contribution worksheet

Calculate one SKU or variant at a time. Enter all cost inputs yourself and write down the assumptions. A blank input is unknown, not zero.

This worksheet is deliberately app-independent. It does not use a saved shipment ledger or describe an app workflow. It exposes the arithmetic so you can check it in a spreadsheet before choosing a discount.

Inputs and units

Use one price currency for selling prices and shopper-facing subsidies, and one cost currency for landed costs. Define FX as cost-currency units per 1 price-currency unit. Write the FX source and date beside the rate.

SymbolInputUnit and assumption
PCurrent or discounted selling pricePrice currency per unit. Use the same tax basis for both prices. This worksheet does not decide whether a price includes VAT or another tax.
CProduct unit costCost currency per unit.
DDuty allocated to the unitCost currency per unit, entered by you. No customs rate is inferred.
FFreight allocated to the unitCost currency per unit. Record the allocation method and shipment total.
IInsurance or other landed amountCost currency per unit, entered by you. Use an explicit zero if it does not apply.
rVariable payment fee rateDecimal in the price-currency calculation. Enter 0.029 for 2.9%. Confirm the fee basis with your provider.
kFixed payment fee allocated to the unitPrice currency per unit. Explain any order-to-unit allocation.
SShipping subsidy allocated to the unitPrice currency per unit. Enter only the amount the store bears in this scenario.
XFX rateCost-currency units per 1 price-currency unit.

Keep returns, advertising, overhead and other excluded costs visible in a notes column. If you want them in the scenario, add an explicit input rather than hiding them in duty or freight.

Formulas

First calculate landed unit cost:

L = C + D + F + I

For each price P, calculate contribution per unit in the cost currency:

contribution(P) = (P - P × r - k - S) × X - L

Compare the two scenarios:

contribution change = contribution(sale price) - contribution(current price)

A negative contribution stays negative. Do not hide it behind a rounded display or a percentage discount. Keep full precision during the calculation and round only the final display values. If you calculate a contribution percentage, state its denominator and how zero denominators are handled.

Worked example

These inputs are fictional. The example assumes EUR selling prices, USD landed costs and 1.08 USD per 1 EUR. It is not a recommended price or a tax calculation.

Input or resultCurrent priceDiscount price
Selling price PEUR 40.00EUR 26.00
Product cost CUSD 9.00USD 9.00
Duty DUSD 2.00USD 2.00
Freight FUSD 1.50USD 1.50
Insurance/other IUSD 0.50USD 0.50
Landed cost LUSD 13.00USD 13.00
Payment fee r0.0290.029
Fixed fee kEUR 0.30EUR 0.30
Shipping subsidy SEUR 4.00EUR 4.00
FX X1.081.08
Contribution per unitUSD 24.3032USD 9.62168

Current contribution is (40 - 40 × 0.029 - 0.30 - 4) × 1.08 - 13 = 24.3032 USD.

Discount contribution is (26 - 26 × 0.029 - 0.30 - 4) × 1.08 - 13 = 9.62168 USD.

The price falls by 35%, while contribution falls by 14.68152 USD per unit under these assumptions. Recalculate with your actual fee basis, FX date and cost allocations before approving the sale.

Blank worksheet

Copy this heading row into a spreadsheet and keep one row per variant and scenario:

SKU, variant GID, price currency, cost currency, FX, FX source and date, current price, discount price, product cost C, duty D, freight F, insurance/other I, payment rate r, fixed fee k, shipping subsidy S, tax basis, freight allocation basis, current contribution, discount contribution, contribution change, exclusions, reviewer notes

Before locking the discount, check that:

The starting observation comes from 695140 post #23: "landed cost doesn't discount along with your sale price". 708800 post #1 discusses freight, duty and insurance allocation and preserving earlier cost layers. Both posts include developer disclosures; neither determines your duty, tax or accounting treatment.

3. Storefront offer and policy consistency audit

Compare pages under the same conditions. A price or policy checked in different markets, currencies, carts or campaign states can look inconsistent without proving a defect.

Fix the test conditions first

Create a condition ID and record:

Use that same condition ID on every page row. If a condition changes, start a new run instead of mixing the evidence.

Compare these seven surfaces

SurfaceWhat to compare with the other pages
PDPPrice, compare-at display, discount amount, sale end, code eligibility, product name, material, shipping and return promise. Check for negative savings and placeholder blocks.
CartSame selected variant and price, discount or gift eligibility, shipping threshold and any return or promotion message shown before checkout.
FAQShipping price and timing, return condition, used-item eligibility, return postage, sale end and code stacking.
Shipping policyDestination coverage, free-shipping threshold, paid rates and delivery estimates for the same market and cart.
Returns policyReturn window, product condition, exclusions, return address and who pays return postage. Compare any PDP promise with this page.
Gift productLive campaign dates, threshold, stock wording, price visibility, description and search metadata. Draft or update stale gift offers deliberately.
Search and collection resultsProduct title, displayed price, stale snippets, gift visibility and placeholder text. Search for the same product and campaign terms used on the PDP.

Do not treat a possible mismatch as a legal violation. Quote both texts, check the conditions and assign someone to confirm the intended customer-facing rule.

Evidence log

FieldWhat to record
Finding and condition IDsStable identifiers that link the finding to the exact audit run.
Page pair and URLsFull URL for each page, including relevant variant or market parameters.
Quoted text or valueExact conflicting text, price, threshold or date from each page.
ScreenshotsOne file per page with the URL and relevant content visible. Use the finding ID in each filename.
Found atDate, time and timezone.
Interpretationconfirmed mismatch, needs review or different test conditions. Do not write illegal as a shortcut.
Owner and correctionNamed reviewer, intended wording or value, and correction made.
Recheck requiredyes or no, the recheck time, and a fresh URL and screenshot after the change.

This fictional row shows the expected level of detail:

FindingPage pair and URLsEvidenceFound atRecheck
BFCM-003, condition AU-MOBILE-01PDP https://example.com/products/towel and FAQ https://example.com/pages/faqPDP says return postage is included; FAQ says the customer pays. Files: BFCM-003-pdp.png, BFCM-003-faq.png. Status: needs review.2026-11-27 22:10 AEDTYes. Recheck both URLs after the owner confirms the policy; save new screenshots and the result.

Run the audit again after corrections and after the campaign ends. Recheck gift products and search snippets because old campaign text can remain after the PDP changes.

The source thread began with a merchant asking what would prevent visitors from adding to cart or checking out. Specific public-page observations include a sale without an end date in post #6, shipping and return-postage conflicts in post #8, stale gift wording and product-data mismatches in post #12, and different shipping and return conditions in post #13. 706450 post #19 reports "Save $-113.89" and a leftover placeholder. These examples guide a manual audit; they do not establish that another store has the same problem today.

Final review boundary

Keep the snapshots, assumptions, URLs, screenshots and recheck results together. Separate an observed value from an interpretation, and an unresolved item from a pass. This guide supports manual operational checks. It does not certify legal compliance, determine customs or tax, or replace review by a qualified adviser.