Free operator sheet · Stays in your browser

Third-Party Channel
P&L.

Run the honest math on DoorDash, Uber Eats, or Grubhub. Gross sales minus commission, marketing fees, refunds, packaging, and the labor those orders cost. Settles the argument.

Pack: Conversions & Reservations Cadence: Monthly Private — runs in your browser

Fill it in

Third-Party Channel P&L

Type your numbers — the math runs in your browser. Print it, save it as a CSV, or save it to your Workshop.

Worked example Single-unit operator running DoorDash + Uber Eats See what a Tuesday-morning fill-in looks like
Gross third-party sales (last 4 weeks)$24,000
Commission + marketing fees (avg 28%)−$6,720
Refunds + adjustments−$480
Packaging cost−$960
Incremental kitchen labor estimate−$1,800
Net contribution after channel costs$14,040
Channel contribution margin58.5% · green
Per dollar of gross third-party revenue$0.585 stays

The channel pencils — but only because their incremental labor estimate is honest. If they were treating delivery orders as 'free' kitchen time, the margin would read closer to 70% and they'd quietly be subsidizing the platform. The next move is the recipe-cost-card on the three SKUs that move 60% of delivery volume — those decide whether the channel stays accretive.

Composite-typical numbers — not a real shop. Use the rhythm, not the figures.

Channel & period
Channel statement (paste from their dashboard)
Your costs (the platform does not show these)
Net payout from platform $0.00
Total channel cost (food + packaging + labor) $0.00
Contribution margin (dollars) $0.00
Effective margin on gross 0.0%

Type your numbers. A positive contribution margin means the channel earns its keep; negative means each order loses money before fixed costs.

Try a scenario — what if commission, marketing, or your labor estimate shifts?

Slide one or more, the contribution margin re-runs on top of your typed numbers. The labor multiplier is the honest one — if you typed $1,800 but the real number is closer to $3,600, slide it to 2x and watch what happens.

Read the long version The headline lie, the five lines you need to count, the contribution-margin bands, and a four-lever renegotiation playbook for when the channel doesn't pencil. The honest channel P&L — Why most operators discover delivery is a subsidy →

+ (Math.round(abs * 100) / 100).toFixed(2); } function fmtPct(v) { var sign = v < 0 ? '-' : ''; return sign + (Math.round(Math.abs(v) * 10) / 10).toFixed(1) + '%'; } // D8 · Read what-if slider state. Commission/marketing are // additive points-of-gross; labor is a multiplier on the typed // incremental_labor line. function whatif() { var f = document.getElementById('sheet-fields'); if (!f || !f.whatif_comm) return { comm: 0, mkt: 0, laborMult: 1 }; var lm = n(f.whatif_labor.value); if (!isFinite(lm) || lm <= 0) lm = 1; return { comm: n(f.whatif_comm.value), mkt: n(f.whatif_mkt.value), laborMult: lm, }; } function recalc() { var f = document.getElementById('sheet-fields'); if (!f) return; var w = whatif(); var gross = n(f.gross_sales.value); // D8 — apply commission/marketing point deltas as a fraction // of gross; labor multiplier scales the typed incremental. var commission = n(f.commission.value) + (w.comm / 100) * gross; var marketing = n(f.marketing_fees.value) + (w.mkt / 100) * gross; var labor = n(f.incremental_labor.value) * w.laborMult; var deducts = commission + marketing + n(f.refunds.value); var costs = n(f.food_cost.value) + n(f.packaging.value) + labor; var payout = gross - deducts; var contrib = payout - costs; var pct = gross > 0 ? (contrib / gross) * 100 : 0; // Update what-if output labels. if (f.whatif_comm_out) f.whatif_comm_out.value = (w.comm >= 0 ? '+' : '') + w.comm.toFixed(1) + 'pt'; if (f.whatif_mkt_out) f.whatif_mkt_out.value = (w.mkt >= 0 ? '+' : '') + w.mkt.toFixed(1) + 'pt'; if (f.whatif_labor_out) f.whatif_labor_out.value = w.laborMult.toFixed(1) + 'x'; document.querySelector('[data-output="net_payout"]').textContent = fmt$(payout); document.querySelector('[data-output="total_costs"]').textContent = fmt$(costs); var dEl = document.querySelector('[data-output="contrib_dollars"]'); dEl.textContent = fmt$(contrib); dEl.dataset.band = contrib > 0 ? 'good' : (contrib < 0 ? 'bad' : 'idle'); var pEl = document.querySelector('[data-output="contrib_pct"]'); pEl.textContent = fmtPct(pct); // D9 — band routes through Bench.evaluate when available, so // updating data/benchmarks.json's channel_contribution_pct // thresholds cascades to this sheet automatically. Inline // ladder is the graceful fallback. if (window.Bench && window.Bench.evaluate) { var bench = window.Bench.evaluate('channel_contribution_pct', pct); if (bench && bench.band) pEl.dataset.band = bench.band; } else { pEl.dataset.band = pct > 5 ? 'good' : (pct >= 0 ? 'warn' : 'bad'); } var verdict = document.querySelector('[data-output="verdict"]'); if (verdict) { if (gross <= 0) { verdict.textContent = 'Type your numbers. A positive contribution margin means the channel earns its keep; negative means each order loses money before fixed costs.'; } else if (contrib < 0) { verdict.textContent = 'This channel is losing you money on each order before fixed costs are even applied. Either renegotiate fees, raise menu prices on this channel, or turn it off.'; } else if (window.Bench && window.Bench.evaluate) { // Centralized message for non-edge bands (>= 0 contrib). var b2 = window.Bench.evaluate('channel_contribution_pct', pct); if (b2 && b2.msg) verdict.textContent = b2.msg; } else if (pct < 5) { verdict.textContent = 'Thin contribution. The channel is not paying for itself once fixed costs (rent, utilities, salaried management) are included. Action: raise menu prices on this channel, or shrink the menu offered through it to higher-margin items only.'; } else if (pct < 12) { verdict.textContent = 'In the typical band for third-party delivery — earning some contribution, but not as much as a dine-in dollar. Watch the trend month-over-month.'; } else { verdict.textContent = 'Healthy contribution for a third-party channel. Keep an eye on packaging and incremental labor — these are the line items that drift quietly.'; } } } function collect() { var f = document.getElementById('sheet-fields'); if (!f) return [['Field', 'Value']]; return [ ['Field', 'Value'], ['Channel', f.channel.value], ['Period', f.period.value || ''], [], ['Gross sales', f.gross_sales.value || '0'], ['Commission & service', f.commission.value || '0'], ['Marketing fees', f.marketing_fees.value || '0'], ['Refunds & adjustments',f.refunds.value || '0'], ['Net payout', document.querySelector('[data-output="net_payout"]').textContent], [], ['Food cost', f.food_cost.value || '0'], ['Packaging', f.packaging.value || '0'], ['Incremental labor', f.incremental_labor.value|| '0'], ['Total channel cost', document.querySelector('[data-output="total_costs"]').textContent], [], ['Contribution margin ($)', document.querySelector('[data-output="contrib_dollars"]').textContent], ['Effective margin (%)', document.querySelector('[data-output="contrib_pct"]').textContent], ]; } // D8 · Reset scenario sliders. document.addEventListener('click', function (ev) { if (ev.target && ev.target.matches && ev.target.matches('[data-whatif-reset]')) { ev.preventDefault(); var f = document.getElementById('sheet-fields'); if (!f) return; if (f.whatif_comm) f.whatif_comm.value = 0; if (f.whatif_mkt) f.whatif_mkt.value = 0; if (f.whatif_labor) f.whatif_labor.value = 1; f.dispatchEvent(new Event('input', { bubbles: true })); } }); if (window.SheetPage) { window.SheetPage.register({ slug: 'third-party-channel-pnl', collect: collect, recalc: recalc, }); } })();

Keyboard: ⌘P print · ⌘S download CSV · ⌘↵ save to Workshop

When to use it

Pull this sheet out when —

  • End of month, when the platforms have settled and you have the real fee picture.
  • When a marketing rep calls and offers "a free promo" — see if it actually breaks even.
  • Before you decide whether to keep one of the three platforms turned on.
Common mistakes

What operators get wrong

  • Treating promo subsidies as revenue. The subsidy ends; the discount habit does not.
  • Ignoring packaging cost. A clamshell, a lid, a sticker, a bag — easily 90 cents per ticket.
  • Forgetting incremental labor. Delivery tickets eat expo and packing time you would not bill direct.
Pairs with

The tools, terms, and articles this sheet sits next to.

Free, no signup. Your numbers never leave this page.