Where the macros come from
MacroMate maintains a Firestore database (Firebase project macromate-34aa9) of menu items across 110+ fast food and casual dining chains. For each item, the database stores: chain, item name, calories, protein, carbs, fat, and goal tags (Cutting / Bulking / Maintenance / Keto / Low Calorie). The same database powers the iOS and Android apps; the website renders a subset of that data into static HTML pages.
Source priority for every macro entry:
- Official chain nutrition data (chain's published nutrition labels, calculator tools, or franchise PDFs). This is the authoritative source whenever it exists.
- Confirmed modifications — a documented order modification ("no bun," "double meat," "lettuce wrap"). Macros are computed by subtracting/adding from the base item using the chain's published values.
- Calculated builds — composite orders (e.g., a Chipotle "MacroMate's Bowl" combining several base items). Macros are summed from each base item's published values.
What we don't do: estimate macros, round liberally, or copy from secondary sources without verification. If we can't get an item's macros from primary sources, the item doesn't ship.
The four automated fact-check gates
Every deploy of this site runs through four gates. Any failure blocks the deploy. All four are required in CI; the code lives in scripts/ in the public repository.
1. Structured data integrityrequired
Verifies all JSON-LD schema is valid, every page has a canonical tag, every title is 30-70 characters, every meta description is 70-180 characters, robots.txt is consistent with sitemap, and the sitemap matches the actual file inventory. Six sub-checks total. Catches the failure mode where a typo breaks schema or a new page goes unindexed.
2. Restaurant reference validityrequired
Walks every blog page looking for restaurant brand-name mentions. Cross-references against the canonical list of 110+ chains we have pages for. Flags any reference to a chain not in our database — preventing hallucinated chain references from appearing in content where we don't have data. The blocklist contains chains we DON'T cover (so writers can't accidentally cite them); the canonical list contains chains we DO cover (so removals are caught). Currently catches 0 violations across 155 pages.
3. Macro drift between hubs and sourcerequired
Walks every cluster hub's ItemList schema (e.g., "Best Macro-Friendly Chicken Fast Food" lists 9 chain picks with macros). For each cited macro pair (calories + protein), verifies a matching SKU exists on the source chain page within ±30 calorie / ±7 gram protein tolerance. Catches the failure mode where a hub cites "440 cal / 62g protein" for an item the chain page actually shows as "445 cal / 50g protein." Currently 0/59 mismatches.
4. Physics sanityrequired
Verifies every MenuItem in the chain page schemas obeys basic thermodynamics. Each gram of protein contributes at least 4 calories of energy, so a 90-calorie item claiming 48g protein is impossible — the protein alone would need 192+ calories. This gate caught 3 corrupted SKUs (since fixed) and now blocks any future Firestore-side data corruption from shipping. Currently 0 violations across 1,627 menu items.
When a gate fails, the deploy stops with an error message naming the offending file and the specific violation. There are escape hatches (SKIP_INTEGRITY=1, SKIP_FACT_CHECK=1, SKIP_PHYSICS=1) but they're for true emergencies only — using them routinely defeats the gate.
How modifications and customizations are handled
Most chain orders on MacroMate are modified versions of base menu items: "no bun," "no fries," "lettuce wrap," "double meat," "no sauce." Each modification's macros are computed from the chain's published values for the base item plus or minus the modifier's documented contribution.
Example: Subway's 6-inch Turkey Breast (cutting build) lists 350 cal / 28g protein in our database. The base item ships with cheese and mayo by default; "no cheese, no mayo, all veggies" subtracts ~80 cal and adds 0g protein, yielding the cutting build we publish. This is a documented modification, not a guess.
When a chain doesn't publish nutrition for a specific modification, we conservatively round in the direction that makes the item LESS macro-friendly — never the opposite. A modification that might be 350 or 365 calories gets recorded as 365. Better to over-report a cutting order's calories than under-report.
What we don't claim
We don't claim medical authority. MacroMate is a macro-tracking and ordering reference, not medical or dietetic advice. We don't recommend specific calorie targets, dose-adjusted protein for GLP-1 users, or any other prescriptive guidance that requires individual assessment. The GLP-1 guide and similar pages are practical ordering references, not medical instructions.
We don't guarantee chain-side accuracy. When a chain changes its menu or reformulates an item, our database lags until we update it. The macros on this site reflect the chain's published nutrition at the time of our last sync. If a discrepancy appears between this site and the chain's own current nutrition label, the chain's current label is authoritative.
We don't pad lists. When a cluster hub says "9 chains ranked," it ranks 9 chains we have full data for — not 9 chains plus 6 we wish we covered. When a leaderboard shows 40 items, those are the 40 highest-ranked items from the 1,627-item database, not a curated highlight reel.
The principles behind the methodology
Real data over plausible-sounding numbers.
The pre-2024 era of LLM-written health content (and the era after) is full of plausible-sounding macros that don't match any actual menu item. We caught ourselves making this mistake during development and built the macro-drift and physics gates as a response. Every published number on this site now traces to a verified source SKU.
Gates over reviews.
Manual review catches obvious errors but misses subtle ones. Automated gates run on every deploy and catch the same class of error every time. We chose the gate approach because it's the only one that scales — if it works on commit 1, it works on commit 1,000.
Removal over fabrication.
When a data error is discovered (like the 3 physically-impossible SKUs the physics gate caught), the response is to remove the corrupted entries — not to guess at corrected numbers. The premise of this entire methodology is that fabricated data is the worst possible outcome. Removing is always safer than guessing.
Audit trail
This site is open-source-friendly in its data layer. The scripts that gate every deploy are visible in the repository:
scripts/technical-seo-integrity.py— structured data + canonicals + sitemap parityscripts/fact-check-restaurants.py— chain reference validityscripts/fact-check-macros.py— hub-vs-chain macro driftscripts/fact-check-physics.py— basic thermodynamics
Each chain page contains the full JSON-LD MenuItem schema for every order we have for that chain. You can verify any macro on this site by reading the chain page's schema directly.
Related Guides
What is Macro-Friendly Fast Food? The 5 Criteria
The framework this methodology applies — the 5 measurable criteria for whether an order is macro-friendly.
Read more →How MacroMate Gets Its Numbers (Deeper Dive)
An earlier, more narrative version of this methodology — focuses on the human side of building the database.
Read more →Live Leaderboard: Highest Protein-Per-Calorie
The Dataset-typed cross-chain leaderboard that this methodology produces.
Read more →What is the Protein-to-Calorie Ratio?
The anchor metric we use to rank every cutting order. Definition + tiered examples.
Read more →