Skip to content
AspirecoStart
All writing

Journal

Freight is the hard part

11 min read

Teams build catalogue, search, pricing and checkout in that order, then leave freight to whatever plugin the platform ships with. On a catalogue of heavy goods, that plugin is the thing deciding whether the order was worth taking.

The difficult part of a large-catalogue ecommerce build is almost never the catalogue. Search is tractable if you are willing to build the ladder properly. Payments are tractable. Even pricing, which on flooring is genuinely awkward, is arithmetic you can write down once and test against production.

Freight is different, because the number depends on facts that live outside your database: what the carrier's tariff says this week, where the delivery is going, whether there is a dock at the other end, whether the goods stack. It is the one figure in the cart that you neither control nor can invent, and on heavy goods it is large enough that getting it wrong is not a rounding error. It is the margin.

The Catalogue Engine pipeline has six stages — Ingest, Index, Price, Rate, Pay, Sync — and Rate is one of them, sitting between the price of the goods and the taking of the money. That placement is the whole argument, so here is the reasoning behind it.

Flat rate is a bet on your average order

Free shipping over a threshold, or a flat fee per order, works when the spread of real shipping costs around your average is narrow. Sell books, or t-shirts, or anything where the heaviest order in a month is a small multiple of the lightest, and a flat rate is a fair simplification. You will be wrong on individual orders and right in aggregate.

Heavy goods break the assumption, because the distribution is not narrow. It is skewed, and the tail is where the revenue is. One customer buys two boxes of tile for a small bathroom. Another buys enough engineered oak for a whole floor, palletised, going to a house with no dock and a liftgate needed at the kerb. Those two orders do not cost the same to move, and the difference is not a percentage: one is a parcel and the other is a pallet on a truck with a tail lift.

That leaves two ways to be wrong, and both are expensive:

  • Price the flat rate for the mean and every large order quietly subsidises itself out of your margin. The orders you most want become the ones that lose the most money, which is a strange incentive to build into a storefront.
  • Price it for the tail and the small orders look absurd beside a competitor who rates live. You lose the top of the funnel to protect the bottom of it.

There is a third option people reach for: a flat rate with exceptions. Heavy items flagged, remote postal codes surcharged, everything else averaged. That is live rating with worse coverage and a table of rules nobody maintains. Once you are writing exceptions you have already conceded that freight is a function of the order. Model it as one.

The weight is lumpy, because you buy boxes

Flooring does not price like retail, and the reason it does not is the same reason freight is hard on it. The customer wants an area — a room, in feet or metres. The supplier sells a box that covers some fraction of that area. Nothing you ship is a square foot.

The pricing engine on Shopflooring resolves that in a fixed order: room dimensions to linear feet, to boxes, to square footage, to a priced estimate, per product type, with the waste factor applied before the box rollup rather than bolted on at checkout. That last detail matters more than it sounds. Waste is a multiplier on area, and area rounds up to a whole box, so applying waste after the rollup can leave the customer a box short of the floor they came to buy. Atelier, the room visualiser, carries the same idea from the other direction: the materials cost estimate it derives from a photo includes a 10% waste factor.

The consequence for freight is that shipped weight is a step function of area, not a line through it. Adding a square metre to the room may add nothing to the shipment, or it may add a full box — and every box is a discrete weight with discrete dimensions. The cart total moves smoothly. The shipment moves in jumps.

That is the whole-box problem, and freight sits immediately downstream of it. You cannot rate an order from its price. You cannot rate it from the area the customer typed. You can only rate it from the boxes, which means the rating call has to run after the box rollup, on its output.

The order of operations, in one line

Area, then waste, then boxes, then weights and dimensions, then the carrier. Any stage that skips one of those is quoting on a number that does not exist.

Dimensional weight, or why a weight column is not enough

Carriers do not bill weight. They bill the greater of two numbers: what the shipment weighs on the scale, and what its volume implies it should weigh — volume divided by a divisor the carrier publishes and revises from time to time.

For dense goods, scale weight wins and the dimensional figure never matters. For bulky light goods — an extractor hood, a bath, insulation, anything that is mostly air inside a large carton — the dimensional figure wins, sometimes by a wide margin. A catalogue holding both has to carry both facts per sellable unit, which means the product record needs carton dimensions and not merely a weight.

This is where catalogue ingestion and freight quietly turn out to be the same problem. Shopflooring normalises twenty-plus supplier price lists into one schema across a catalogue of 118,000-plus products. Those lists do not agree with one another about what a unit is, let alone about carton dimensions, and a rating engine handed a missing dimension will either fail or guess. So the build carries a density and weight calibration derived per category: where a supplier gives you real carton data you use it, and where they do not you fall back to something defensible for that category rather than to a global default that is wrong for half the catalogue.

Freight accuracy, in other words, is mostly a data problem inherited from the Ingest stage. The carrier integration is the easy half.

Parcel stops, freight starts, and the rules change

Every parcel carrier has a ceiling — a weight per piece and a size per piece, both published in its tariff. Below it you are in the parcel network: pricing scales fairly smoothly, the label is cheap, the delivery is unattended. Above it you are in LTL freight, and almost nothing carries across.

In LTL:

  • The unit of pricing is the pallet and the weight band, not the item.
  • Density and freight class matter, so a light bulky pallet can cost more to move than a heavy compact one.
  • Accessorials are where the money goes — residential delivery, liftgate, appointment booking, limited access, inside delivery, notification before arrival. Those are facts about the destination and the receiver, not about the product.

The last point is the one that catches storefronts out. You cannot rate a freight shipment from the cart alone. You need the destination, and you need to know whether the person receiving it has a loading dock or a driveway. A rating call that asks for a commercial delivery and then delivers to a house has not quoted the shipment. It has quoted a different shipment that happens to contain the same goods.

Once it is freight, you are pricing pallets

Inside LTL the cost driver is space and weight banded together, so the arithmetic the storefront owes the carrier before it calls is consolidation: given these boxes, how many pallets, how tall, how heavy each.

Getting that wrong hurts in either direction.

ApproachWhat happens
Rate each line separately and sumYou quote several shipments for one delivery. The large order, the one you wanted, prices itself out.
Rate a single pallet regardless of quantityYou underquote everything past the first pallet and pay the difference yourself.
Consolidate, then rate the palletsThe quote matches the shipment the carrier will actually collect.

Banded pricing also produces a result that looks like a defect and is not: crossing into a higher weight band can lower the total, because the rate per pound drops at the break. An engine that does not know the bands exist will quote the higher number and never notice it did. On a heavy catalogue that is not an edge case, it is a Tuesday.

Why the quote has to happen before checkout

Rate sits before Pay in the pipeline. Four reasons that ordering is not negotiable.

It is a material part of the price. On large-ticket goods the freight line is not a garnish on the total. Revealing it after the card details is the ecommerce equivalent of a surprise service charge, and customers respond the way you would expect them to.

Quoting afterwards turns an order into a thread. The moment freight becomes "we will confirm by email", the checkout has been replaced by a conversation, a delay and a second consent — precisely the machinery the storefront was built to remove.

Financing needs a final number. Shopflooring offers Klarna, Afterpay and Affirm through Stripe so that large-ticket orders have a financing path at the point of decision. A financing plan is created against a total. You cannot amend that total afterwards without unwinding the plan, so the freight figure has to be inside the amount before the customer is handed over. Rate the order after payment and the financing path does not exist for you at all.

A second charge is a second chance to fail. Capturing the goods now and the freight later means a card-not-present authorisation days after the intent has cooled, on a card that may have moved on — and somebody in your business chasing it when it does not go through.

The corollary is that rating belongs on the server. Shopflooring rates through Freightcom, and one API serves the web store and the native Android client, so there is one source of truth and one place a tariff change lands.

When you cannot rate it, say so

Some shipments will not rate live, and pretending otherwise is worse than admitting it. Oversize pieces, remote destinations, mixed loads that do not cut into clean pallets, deliveries into buildings with rules of their own. These need a person or a quote request, and the honest design is a path that says "we will come back to you with a number" rather than a plausible number generated to keep the flow tidy.

Norpex is built around that admission. Commercial kitchen equipment is a quote business pretending to be a catalogue business: buyers want specification help and freight figures before they will commit, and sellers are small distributors who will not adopt a platform that takes a week to join. So the marketplace routes quote requests by product category to the right vendor with a tracked reply path, and keeps one checkout across every vendor for the things that can simply be bought. Two mechanisms, honestly separated, instead of one mechanism quietly lying about half the catalogue.

Where this leaves the build order

If you are replatforming a heavy catalogue, the sequence that works is not the one that feels natural, because freight accuracy is decided upstream of the freight integration.

  1. Ingest supplier data with carton weights and dimensions treated as required fields, and a per-category calibration where the source data is thin.
  2. Price through a box rollup, waste applied before the rollup, so the order is described in the only unit that actually ships.
  3. Rate against consolidated pallets and the real destination, server-side, before the total is shown.
  4. Pay on a number that already includes freight, which is the only way the financing options are open to you.

Carrier APIs are well documented and wiring one up is the predictable part of the job. The weight model underneath it is the part that takes the thinking, and it is the part that decides whether your best orders are the ones you make money on.

The Catalogue Engine is available as a build or on a retainer, and the marketplace variant sits next to it. If you are carrying a catalogue where price is a calculation rather than a column, the brief will tell you which of those it looks like.

Want this run against your own numbers?

Start the audit