How we score
Short version: we read the ingredient list on the label, grade every single ingredient, and add up what looks like a nutritious bowl and what looks like marketing. The same rules are applied to every product, with no per-product human override.
Evidence behind the score
The ingredient tiers and processing weights are grounded in peer-reviewed studies and veterinary guidance, not just brand marketing. We keep a living list of the sources that inform the model.
The five steps, in plain English
- We read the label. We take the ingredient list exactly as it is printed on the bag or tin, word for word.
- We work out how much is in it. UK law only requires percentages for the headline ingredients. For the rest, we use the order of the list. By law, ingredients are listed from heaviest to lightest, so a longer list position means less.
- We grade every ingredient. Each of the 963 known ingredients is graded as good, medium or poor. Named meats and fish score well; cheap fillers, artificial colours and vague “by-products” score badly.
- We add it all up. Good ingredients pull the score up. Fillers, additives and undeclared “other” stuff pull it down. Labels that print real percentages get a small bonus for transparency.
- We sanity-check the results. Clearly excellent recipes should land at the top and clearly filler-heavy ones at the bottom, and that is what the model produces. You can read the label yourself and see why a product scored the way it did.
The five dimensions
The 1-100 headline is the Recipe score, computed with the same rules as before; the coefficients were re-calibrated, so individual scores may have moved by a few points. Four further dimensions sit alongside it on every product page, each computed from stored data and expandable to show its working.
Recipe (the headline score)
Ingredient quality and specificity, dry-matter composition, transparency of printed quantities, processing type and additives. This is the published 1-100 score, and the only dimension that feeds the headline number.
Nutritional
How the declared analytical constituents compare with FEDIAF reference ranges, scored on a dry-matter basis. Confidence markers (high, medium, low) show how much was actually declared; missing data is shown, never imputed silently.
Transparency
How much the manufacturer discloses, measured against the FEDIAF Code of Good Labelling Practice and Regulation 767/2009. Mandatory items dominate the weighting.
Safety
Recall and safety-notice history, time-decayed. This dimension never feeds the headline score, and the incident list is always shown next to the number.
Evidence
How much evidence supports the claims made on the pack and product page: manufacturer assertion versus cited research. No claims on file means "nothing to verify", not a zero.
The evidence for each rule
Every scoring decision above exists because of a specific piece of published evidence - not because it sounds right. The full source list lives on the research page.
Named cuts beat bare species names
“Chicken breast / beef liver” score higher than plain “chicken / beef”, which could legally be frames or mechanically recovered meat.
Why: Protein quality varies enormously with the actual tissue used; unspecified sources cannot be judged.
Dry-matter normalisation
Percentages are compared on a dry-matter basis: fresh meat is ~72% water, meat meal ~8%, so wet and dry recipes are converted before comparison.
Why: Comparing as-fed percentages flatters wet foods; moisture changes misrepresent nutrient content.
Fresh frozen & raw rank above kibble
Minimally processed formats get a scoring advantage over high-heat extruded kibble.
Why: Frozen raw, freeze-dried and fresh diets showed higher amino-acid digestibility and metabolisable energy than extruded food; fresh foods keep more available lysine and fewer AGEs than kibble.
Shelf-stable “fresh” gets no fresh bonus
Ambient-stable fresh food (steam-cooked in a sealed pack, e.g. retorted trays) is scored on recipe alone - no minimal-processing advantage.
Why: Retort sterilisation is process-wise identical to canning. Wet/retorted foods had the worst AGEs and lysine damage of all formats tested; in human food, canning causes the largest heat-labile vitamin losses and multiplies AGEs.
Extrusion & high-heat drying drag scores down
Extruded and baked dry foods rank below gently processed formats.
Why: Extrusion and 160–180°C drying measurably reduce available lysine and other nutrients.
Additive penalties are moderate, not extreme
Artificial colours are penalised most (they exist only to impress buyers); approved preservatives get small penalties.
Why: A systematic review found approved additives show no measurable harm within regulatory limits - so we penalise non-disclosure and cosmetic additives, not safety.
Grain-inclusive is not penalised per se
Grains are fine as part of a recipe; only filler dominance (high carb, low meat) drags a score down.
Why: Controlled trials found no DCM signal or taurine effect from grain-free vs grain-inclusive diets; formulation quality matters more than grain ideology.
Transparency is rewarded three times
Printing some percentages earns a clear-label bonus; ~fully quantifying the recipe (95%+ of mass declared) earns a full-disclosure bonus; declaring exactly which additives are used (with doses) earns a small transparency bonus.
Why: A label that discloses quantities lets you verify the recipe - the whole basis of this site. Undeclared products are not penalised beyond missing the bonuses, since not publishing is not proof of poor quality.
What lifts a score
- A high share of named meat, fish and meat meal
- Vegetables, fruit and useful oils instead of fillers
- A clear, honest label with percentages printed for (nearly) every ingredient
- Declaring exactly which additives are used (small transparency bonus)
- Few or no artificial colours, flavours and preservatives
What drags a score down
- Filler-heavy recipes - wheat, maize or rice making up most of the bowl
- Vague ingredients such as “meat derivatives” or “animal by-products”
- Artificial additives and colourings
- A lot of the recipe not declared by weight
What the headline score does not look at
The 1-100 headline is the Recipe score: it ignores the price, the brand's reputation, the bag design and whether a specific dog happens to be allergic to something. A cheap food with a great ingredient list can outscore an expensive one, and vice versa. Recall history and claim evidence are shown separately in the Safety and Evidence dimensions and never feed the headline number.
Advanced: the exact model, data and weights
For the curious: this is the precise, reproducible machinery behind the plain-English version above.
The full pipeline
- Parse the ingredient list as declared on the packaging, extracting percentages where present and expanding grouped ingredients (e.g. Chicken 60% (Chicken, Chicken Liver)).
- Strip marketing terms. Words like premium, natural, human-grade, free-range carry no nutritional information and are removed before matching.
- Estimate missing quantities. The undeclared remainder is distributed across the remaining ingredients, weighting earlier-listed ingredients more heavily (labels list ingredients in descending order of weight).
- Match each ingredient against the glossary of 963 ingredients, each classified (meat, carb, oil, veg, supplement, additive…) and tiered from published nutritional guidance.
- Compute features: category percentages, average ingredient-quality score, count and share of poor ingredients, clear-label flag, additive penalties, processing type.
- Predict the rating with a linear model. The exact weights are listed below, and every score on this site can be recomputed from them.
Current model
- Version
- v2 live
- Type
- linear
- Features
- 40
- Trained
- 2026-09-05
- Weights hash
3ba8a7f5861bf20e…
How the model is calibrated
The coefficient table below is not hand-tuned per product, and it is not fitted to health outcomes. It is fitted against our pinned v1 baseline algorithm, which encodes our editorial judgements about what a good label looks like. This makes the model internally consistent with those judgements, not externally validated against health outcomes. That distinction matters: the score is a reproducible reading of the label, not a proven prediction about your dog.
When a new version is trained, we measure how far its scores drift from the v1 baseline across the whole catalogue, and any drift has to be explained in the release note before the version can be published. We deliberately do not publish the error figures: they measure agreement with our own earlier algorithm, not accuracy against any external truth, and a small number would read as more validation than it is.
Model changelog
Named algorithm versions. One version is live on the site at a time; drafts are trained and tested locally before being published. Every release has a public write-up of what changed and why.
Model coefficients
The exact weights applied to each Recipe feature (plus per-processing-type terms). Every stored rating keeps its full feature vector, so any score can be recomputed from this table. The other four dimensions use fixed published parameters rather than learned coefficients; they ship in the same published weights file under their own blocks.
| Feature | Coefficient |
|---|---|
| Base score (bias) | 32.3358 |
| Average ingredient quality (avgIngredientScore) | 9.9153 |
| Meat share of dry matter (meatPctDM) | 0.1160 |
| Carb share of dry matter (carbPctDM) | -0.1126 |
| Oil share of dry matter (oilPctDM) | -0.0883 |
| Vegetable share of dry matter (vegPctDM) | -0.0018 |
| Additive share of dry matter (additivePctDM) | 0.1772 |
| Supplement share of dry matter (supplementPctDM) | -0.0089 |
| Other share of dry matter (otherPctDM) | -0.3710 |
| Unrecognised share of dry matter (unknownPctDM) | -0.0224 |
| Recipe graded poor (poorPct) | -0.0447 |
| Poor-quality meat in recipe (poorMeatPct) | -0.1819 |
| Number of poor ingredients (poorCount) | -0.8680 |
| Largest single poor ingredient (poorMaxPct) | 0.0564 |
| Undeclared quantities (missingPct) | -0.1309 |
| Prints ingredient percentages (clearLabel) | 3.1945 |
| Complete diet (complete) | 1.7032 |
| Frozen or chilled fresh (isFresh) | 11.4401 |
| High meat (30%+ of dry matter) (highMeat) | -0.5058 |
| Low meat (under 10% of dry matter) (lowMeat) | -1.9883 |
| High carb and low meat (highCarbLowMeat) | -1.2497 |
| Meat share × printed percentages (meatClearLabel) | -0.0733 |
| Meat share × fresh (meatFresh) | -0.3386 |
| Fresh × high meat (freshHighMeat) | 16.4755 |
| Additive penalty (additivePenalty) | 0.2356 |
| Processing multiplier (processingMult) | 32.3358 |
| Processing: Raw (proc_raw) | 13.3220 |
| Processing: Fresh Chilled (proc_fresh-chilled) | 7.7119 |
| Processing: Fresh Frozen (proc_fresh-frozen) | 6.5831 |
| Processing: Fresh Refrigerated (proc_fresh-refrigerated) | 4.8570 |
| Processing: Fresh Shelf (proc_fresh-shelf) | 0.0721 |
| Processing: Dry Freeze Dried (proc_dry-freeze-dried) | 11.1272 |
| Processing: Dry Air Dried (proc_dry-air-dried) | 9.3200 |
| Processing: Dry Cold Pressed (proc_dry-cold-pressed) | 4.5685 |
| Processing: Dry Baked (proc_dry-baked) | -2.3206 |
| Processing: Dry Extruded (proc_dry-extruded) | -6.9960 |
| Processing: Dry Semi Moist (proc_dry-semi-moist) | -6.8331 |
| Processing: Dry Muesli (proc_dry-muesli) | -10.7109 |
| Processing: Wet Pate (proc_wet-pate) | 2.9350 |
| Processing: Wet Chunks (proc_wet-chunks) | 2.2925 |
Ingredient glossary
| Category | Tier | Count |
|---|---|---|
| additive | good | 4 |
| additive | medium | 21 |
| additive | poor | 34 |
| carb | good | 16 |
| carb | medium | 53 |
| carb | poor | 25 |
| fibre | good | 12 |
| fibre | medium | 32 |
| fibre | poor | 3 |
| meat | good | 156 |
| meat | medium | 78 |
| meat | poor | 14 |
| mineral | good | 9 |
| mineral | medium | 11 |
| oil | good | 25 |
| oil | medium | 19 |
| oil | poor | 2 |
| other | good | 3 |
| other | medium | 21 |
| other | poor | 7 |
| other | unknown | 1 |
| supplement | good | 137 |
| supplement | medium | 43 |
| supplement | poor | 5 |
| veg | good | 172 |
| veg | medium | 58 |
| veg | poor | 2 |
Assumptions register
Every score rests on the assumptions below. Each is a deliberate choice, listed with what breaks if it turns out to be wrong for a given product.
| Assumption | Why we make it | What breaks if it is wrong |
|---|---|---|
| Missing moisture is estimated per ingredient category | Labels only have to print moisture above 14%. Estimating it lets wet and dry foods be compared on a dry-matter basis. | That product's composition shares shift. Scores move a little; rankings between similar products rarely do. |
| Undeclared quantities are estimated from list order | UK law requires percentages only for headline ingredients, but does require the list itself in descending order of weight. | The split between minor ingredients is approximate. Printed percentages are always used exactly as declared. |
| Processing type comes from storage instructions, not the product name | "Fresh" on the bag can mean frozen, chilled or shelf-stable retort, which are very different processes. | A misclassified product gets the wrong processing adjustment. The storage instructions are shown on the product page so you can check. |
| "Complete" and "complementary" are taken at label value | These are legal declarations made by the manufacturer; we do not test any product ourselves. | A complementary food could be presented as complete or vice versa. Report it and we correct the record. |
| Additive transparency counts presence, not doses | Whether a label lists "Vitamin A" or "Vitamin A 1,500 IU/kg", the only signal reliably available across the whole catalogue is that the section exists. | A bare list of names gets the same small transparency credit as a fully dosed one. |
Check a score yourself
Every number in a score is published, so you can check the arithmetic with a calculator:
- Open the product page and expand "Recipe: how the 1-100 score is calculated". Each row shows the feature value taken from the label, the published coefficient, and the contribution that results from multiplying them.
- Add the contributions together with the processing-type offset and any label bonuses. If the total lands above 100 or below 1, it is pulled back to 100 or 1; otherwise it stays as it is. The result should match the displayed score; contributions are rounded to two decimals, so allow a rounding difference.
What you can check this way is the arithmetic: every contribution comes from the published coefficient table, and nothing else feeds the score. The one step you cannot redo by hand is turning the raw label into feature values in the first place: that relies on the dry-matter conversion and list-order estimation described above, whose per-category figures are not published.
The weights for every published version are kept, and historical scores stay checkable under their original version. If your recomputation differs from the site, tell us: we treat it as a bug and answer publicly.
Brand attribution
Products are matched to their manufacturer brand from the product name, URL and ingredient list. Every assignment is stored with a timestamp and a confidence, so you can audit it in the provenance section of any product page. Errors are possible, and provenance lets you check each one.