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.
| Check | What to do | Evidence to keep |
|---|---|---|
| 1. Snapshot variant identity | Before 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 outcomes | Give 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 end | After 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 collisions | Immediately 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 history | Treat 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 separately | Record 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 GID | Market | Intended price | Expected restored price | Read-back price | Outcome | Next action |
|---|---|---|---|---|---|---|
gid://shopify/ProductVariant/41000000000001 | Germany / EUR | 26.00 | 40.00 | 40.00 | applied | None |
gid://shopify/ProductVariant/41000000000002 | Germany / EUR | 26.00 | 40.00 | 31.00 | failed | ERP 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.
| Symbol | Input | Unit and assumption |
|---|---|---|
P | Current or discounted selling price | Price currency per unit. Use the same tax basis for both prices. This worksheet does not decide whether a price includes VAT or another tax. |
C | Product unit cost | Cost currency per unit. |
D | Duty allocated to the unit | Cost currency per unit, entered by you. No customs rate is inferred. |
F | Freight allocated to the unit | Cost currency per unit. Record the allocation method and shipment total. |
I | Insurance or other landed amount | Cost currency per unit, entered by you. Use an explicit zero if it does not apply. |
r | Variable payment fee rate | Decimal in the price-currency calculation. Enter 0.029 for 2.9%. Confirm the fee basis with your provider. |
k | Fixed payment fee allocated to the unit | Price currency per unit. Explain any order-to-unit allocation. |
S | Shipping subsidy allocated to the unit | Price currency per unit. Enter only the amount the store bears in this scenario. |
X | FX rate | Cost-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 result | Current price | Discount price |
|---|---|---|
Selling price P | EUR 40.00 | EUR 26.00 |
Product cost C | USD 9.00 | USD 9.00 |
Duty D | USD 2.00 | USD 2.00 |
Freight F | USD 1.50 | USD 1.50 |
Insurance/other I | USD 0.50 | USD 0.50 |
Landed cost L | USD 13.00 | USD 13.00 |
Payment fee r | 0.029 | 0.029 |
Fixed fee k | EUR 0.30 | EUR 0.30 |
Shipping subsidy S | EUR 4.00 | EUR 4.00 |
FX X | 1.08 | 1.08 |
| Contribution per unit | USD 24.3032 | USD 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:
- Duty, FX, freight, insurance and fees are explicit inputs with sources or notes.
- Current and discount prices use the same currency, tax basis and unit quantity.
- Freight and other shared costs have a documented per-unit allocation.
- Empty cells remain unresolved; intended zeroes are entered as zero.
- Negative and near-zero contribution rows have a named reviewer.
- A second person can reproduce the result from the saved inputs and formulas.
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:
- Date, time and timezone for the audit run.
- Market or country, currency, language and selected variant.
- Device, viewport, browser and whether the session is signed out or incognito.
- Cart contents, quantities, discount code, gift threshold and shipping destination used for comparisons.
- Campaign start and end settings being tested.
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
| Surface | What to compare with the other pages |
|---|---|
| PDP | Price, compare-at display, discount amount, sale end, code eligibility, product name, material, shipping and return promise. Check for negative savings and placeholder blocks. |
| Cart | Same selected variant and price, discount or gift eligibility, shipping threshold and any return or promotion message shown before checkout. |
| FAQ | Shipping price and timing, return condition, used-item eligibility, return postage, sale end and code stacking. |
| Shipping policy | Destination coverage, free-shipping threshold, paid rates and delivery estimates for the same market and cart. |
| Returns policy | Return window, product condition, exclusions, return address and who pays return postage. Compare any PDP promise with this page. |
| Gift product | Live campaign dates, threshold, stock wording, price visibility, description and search metadata. Draft or update stale gift offers deliberately. |
| Search and collection results | Product 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
| Field | What to record |
|---|---|
| Finding and condition IDs | Stable identifiers that link the finding to the exact audit run. |
| Page pair and URLs | Full URL for each page, including relevant variant or market parameters. |
| Quoted text or value | Exact conflicting text, price, threshold or date from each page. |
| Screenshots | One file per page with the URL and relevant content visible. Use the finding ID in each filename. |
| Found at | Date, time and timezone. |
| Interpretation | confirmed mismatch, needs review or different test conditions. Do not write illegal as a shortcut. |
| Owner and correction | Named reviewer, intended wording or value, and correction made. |
| Recheck required | yes or no, the recheck time, and a fresh URL and screenshot after the change. |
This fictional row shows the expected level of detail:
| Finding | Page pair and URLs | Evidence | Found at | Recheck |
|---|---|---|---|---|
BFCM-003, condition AU-MOBILE-01 | PDP https://example.com/products/towel and FAQ https://example.com/pages/faq | PDP 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 AEDT | Yes. 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.