Free Canadian Food Inflation Index — Methodology
Version 1.1 — Hybrid Storage + Multi-Basket + X-13 SA Published at canadianfoodindex.ca
1. Scope
The Free Canadian Food Inflation Index is a publicly accessible measure of Canadian food price inflation, computed as a confidence-weighted blend of three independent sources. Version 1.1 stores raw monthly index levels per snapshot and derives multiple views (basket × adjustment × window × period range) at request time; see § 2.4 for the derivation matrix.
Coverage at v1.1:
- Geography: National Canada (no provincial or per-retailer banner breakdown at this version; per-banner readings ship as a separate published surface in a future release)
- Baskets:
food_combined(default; the StatsCan combined Food rollup — the headline reading),food_stores(groceries; food purchased from stores), andfood_restaurants(eating out; food purchased from restaurants). Each basket carries its own snapshot file with NSA and SA series; SA is StatsCan-published forfood_combinedand X-13ARIMA-SEATS-derived for the sub-baskets (see § 2.4) - Periods: Canonical grammar is
YYYY-MM(monthly; e.g.,2026-04), because Statistics Canada and Bank of Canada both publish CPI series at monthly cadence. Quarterly aggregates (YYYY-Qn) and yearly aggregates (YYYY) are also supported. Weekly and daily periods are not published — weekly belongs to the per-banner surface (a separate release); daily has no upstream signal to publish - Cadence: Refreshes on the publication schedule of the upstream Statistics Canada CPI Food Component and Bank of Canada CPI all-items series (monthly; typically third Tuesday of the following month)
Out of scope at v1.1:
- Per-retailer banner-level or sub-category breakdowns (a separate per-banner weekly snapshot is published in a future release)
- Real-time intra-day pricing data
- Provincial decomposition
- Imputation for missing categories within the StatsCan or BoC series
2. Data Sources
Three independent sources contribute to the blended reading. Each is documented with its upstream attribution, methodology link, and licence.
2.1 Statistics Canada — CPI Food Component
- Source: Statistics Canada Table 18-10-0004-01 (Consumer Price Index, monthly, not seasonally adjusted, food component)
- Licence: Statistics Canada Open Licence
- Attribution: "Adapted from Statistics Canada, Consumer Price Index, Table 18-10-0004-01 (Open Licence). Statistics Canada does not endorse this product."
- Methodology pedigree: Published methodology, peer-reviewed, audited by the National Statistician. The benchmark consumers and regulators recognize for Canadian food price inflation.
- Cadence: Monthly publication, typically third Tuesday of the following month
- Authoritativeness rank in this blend: Highest (base weight 0.45)
2.2 Bank of Canada — CPI All-Items (Valet Web Service)
- Source: Bank of Canada Valet Web Service, series V41690973 (Consumer Price Index, all-items)
- Licence: Bank of Canada Valet Terms of Use
- Attribution: "Adapted from Bank of Canada Valet Web Service, series V41690973 (CPI all-items). Bank of Canada does not endorse this product."
- Methodology pedigree: Strong central-bank pedigree. Covers ALL items in the CPI basket — not specifically food. Included as a cross-check on the directional accuracy of the StatsCan food-component reading; deviation between BoC all-items and StatsCan food indicates whether food prices are tracking the broader CPI or diverging
- Cadence: Monthly publication (released alongside or shortly after StatsCan CPI release)
- Authoritativeness rank in this blend: High (base weight 0.35; lower than StatsCan because the basket alignment is weaker)
2.3 Internal Price-History Source
- Source: Project-internal
price_historytable populated by the daily-collection pipeline (parser-driven shelf-price observations across the products the pipeline currently tracks) - Licence: Internal (no third-party constraint)
- Attribution: "Computed from the grocery_pipeline project's own price-history observations. Not a substitute for Statistics Canada's published CPI."
- Methodology pedigree: Transparent observation methodology. The "value" is a basket-weighted average of per-product month-over-month percentage changes. Per-product baselines at or below zero are skipped (would produce divide-by-zero). At least one product must have both a baseline and a current observation for a non-fallback reading
- Cadence: Daily collection capability; aggregated to the period the consumer queries
- Authoritativeness rank in this blend: Lowest (base weight 0.20). Future cycles that validate the internal basket composition against StatsCan food-component weights may raise this weight
2.4 Multi-view derivation matrix
Per ADR-0013 v4, the producer stores raw monthly index levels in every snapshot rather than only a pre-computed YoY value. Consumers derive views from those levels at request time. Four orthogonal dimensions span the view space:
| Dimension | Values | Source of truth |
|---|---|---|
| Basket | food_combined, food_stores, food_restaurants | One snapshot file per basket |
| Adjustment | nsa (raw), sa (seasonally adjusted) | Each snapshot's levels block carries both |
| Window | standard (YoY), trailing3 (3-month-trailing YoY) | Derived per request from the stored level series |
| Period range | Any [from, to] sub-window of the stored 15-month block | Filtered per request by the /levels endpoint |
Per-basket vector ids. Each basket maps to a StatsCan vector id from table 18-10-0004-01:
| Basket | NSA vector | SA vector / source |
|---|---|---|
food_combined | V41690974 | V41690915 (StatsCan SA cube 18-10-0006) |
food_stores | V41690975 | derived in-house via X-13ARIMA-SEATS from NSA |
food_restaurants | V41691046 | derived in-house via X-13ARIMA-SEATS from NSA |
SA provenance. Each SA series declares one of two sa_provenance values:
| Provenance | Meaning | Baskets at this version |
|---|---|---|
statscan_published | Fetched from a StatsCan SA cube (table 18-10-0006, vector 41690915 for the combined food rollup). Highest-fidelity SA; matches what StatsCan publishes. | food_combined |
x13_derived | Derived in-house from the NSA series via X-13ARIMA-SEATS (US Census Bureau, public domain). Stamped with x13_spec_version so a future spec bump is differentiable. StatsCan does not publish SA cubes for the sub-baskets. | food_stores, food_restaurants |
The /yoy and /levels endpoints surface sa_provenance on every response so a consumer can audit whether the SA they're reading is StatsCan's own or our X-13 derivation.
Storage windows. Each snapshot's levels block carries the most recent 15 months of NSA + SA points (LEVELS_STORAGE_WINDOW_MONTHS = 15). The producer fetches 60 months from upstream per refresh (LEVELS_FETCH_INPUT_WINDOW_MONTHS = 60) so X-13 has enough input history for stable seasonal estimates; only the last 15 land in storage. The 15-month window covers both the standard YoY lookback (12 months) and the 3-month-trailing YoY window (15 months total).
Revision tracking. When the producer re-fetches a period that already has a snapshot, deltas per level point that exceed REVISION_DETECTION_EPSILON = 0.005 are appended to a per-(basket, period) JSONL revision log. Anything below the epsilon is round-trip float noise (StatsCan publishes levels to 1 decimal place; 0.005 is half the smallest publishable digit).
3. Blending Formula
Each source's effective weight in the blend is the product of three multiplicative factors:
3.1 Base weights
Weights sum to 1.0 for readability; the blender re-normalizes by the actual contributing weights, so the absolute scale does not matter — only the ratios.
3.2 Fallback factor
When a source could not fetch fresh data, the fetcher returns a fallback sentinel rather than raising. The blender retains the source in the per-source transparency surface but scales its contribution by:
A fallback source contributes 5% of its base weight. This bounds the contamination from a wild sentinel value: with the three sources defined here, if two are fresh at 3.0% and one falls back to 0.0%, the blend lands in the range 2.88–2.96% depending on which source fell back — within 0.12 percentage points of the all-fresh 3.0% reading regardless.
3.3 Freshness decay
Older readings contribute less. The decay is exponential with a 30-day half-life:
A source refreshed today contributes at full effective weight (factor = 1.0). A source 30 days stale contributes at half effective weight (factor = 0.5). A source 60 days stale contributes at one quarter (factor = 0.25). The 30-day half-life is anchored to the monthly publication cadence of StatsCan and BoC: a source one publication cycle stale deserves half its weight.
3.4 Weighted average
If all effective weights sum to zero, the blended value is 0.0. With the published base weights (0.45, 0.35, 0.20), even an all-fallback scenario still produces a defined blend at 5% effective contribution per source. The zero-weight branch is reachable only when a source's source_name is not in SOURCE_BASE_WEIGHTS (an unknown source rolled in from a corrupted snapshot), in which case its base weight resolves to 0.0 and contributes nothing.
3.5 Source agreement scalar
A 0.0-to-1.0 transform of the variance across NON-FALLBACK sources. Let be the set of sources with :
- variance = 0 → agreement = 1.0 (full agreement)
- variance = 100 → agreement = 1/e ≈ 0.37
- variance → ∞ → agreement → 0.0
If fewer than 2 non-fallback sources are present, agreement is 1.0 by definition (nothing to disagree with).
3.6 YoY derivations from stored levels
Given a stored level series for a (basket, adjustment) tuple, the supported window derivations are:
Standard YoY — point-to-point year-over-year:
3-month-trailing YoY — smooths short-run noise by averaging three consecutive months on each side of the 12-month lookback:
where — for the trailing-3 average, .
Single-source derivation. Both /yoy and /levels derive from per_source.statscan_cpi_food.levels exclusively (vector 41690974 NSA / vector 41690915 SA for food_combined; sub-basket vector ids per the per-basket table in § 2.4). The three-source blend (StatsCan + BoC + internal) in §§ 3.1–3.5 above applies ONLY to the headline value served at /series for a single (period, basket). Multi-period derivations cannot blend because BoC publishes all-items CPI (not food specifically) and the internal source reports change-rates rather than a monthly level series. This is a methodology choice surfaced as a transparency note on the filter UI; every reading is labelled with its source.
Both derivations require contiguous monthly periods across the lookback window and a strictly positive anchor (denominator). If either guard fails, the /yoy endpoint returns 422 YOY_DERIVATION_FAILED rather than a misleading number.
The same stored levels back BOTH window choices for BOTH adjustment series — no pre-computation, no separate storage, no rebuild required when a new window definition is added.
4. Worked Example
Suppose for period 2026-04 basket food_combined, the three sources return:
| Source | Value | Freshness lag | Fallback? |
|---|---|---|---|
| StatsCan CPI Food | 3.20 | 5 days | No |
| Bank of Canada CPI | 2.80 | 5 days | No |
| Internal price history | 4.10 | 1 day | No |
Effective weights
- StatsCan:
0.45 × 1.00 × 2^(-5/30)=0.45 × 1.00 × 0.891≈0.401 - BoC:
0.35 × 1.00 × 0.891≈0.312 - Internal:
0.20 × 1.00 × 2^(-1/30)=0.20 × 1.00 × 0.977≈0.195 - Sum:
≈ 0.908
Blended value
(3.20 × 0.401 + 2.80 × 0.312 + 4.10 × 0.195) / 0.908
= (1.283 + 0.874 + 0.800) / 0.908
= 2.957 / 0.908
≈ 3.26%
Source agreement
- mean =
(3.20 + 2.80 + 4.10) / 3=3.367 - variance =
((3.20-3.367)² + (2.80-3.367)² + (4.10-3.367)²) / 3=(0.028 + 0.321 + 0.537) / 3≈0.295(values rounded to 3 decimals; exact arithmetic against the unrounded mean 3.3667 yields the same 0.997 agreement) - agreement =
exp(-0.295 / 100)≈ 0.997
A reading where sources agree to within 1 percentage point yields an agreement scalar near 1.0 — high confidence the blended value is methodology-stable.
5. Source Agreement Interpretation
The source_agreement scalar is the headline trustworthiness signal. Consumers use it to gauge whether to act on the blended value or to dig into per-source contributions before making a decision:
| Agreement | Interpretation | Consumer action |
|---|---|---|
| ≥ 0.95 | Sources concur within ~3 percentage points; blended value is methodology-stable | Use blended value directly |
| 0.80–0.95 | Material disagreement (~5–10 percentage points); blended value smooths over a real methodology gap | Read per-source values; understand which source drives the divergence |
| < 0.80 | Severe disagreement (10+ percentage points); blended value may obscure methodology disagreement | Treat blended value as provisional; investigate via per-source detail |
The per-source contribution dictionary in the API response always carries every source (including fallbacks) with its raw value and freshness timestamp so consumers can audit the blend at any agreement level.
6. Coverage Gaps
This section documents what v1.1 does NOT do, so consumers and reviewers know the boundaries.
- Not banner-level: This index is national. Per-retailer banner readings (Loblaw vs Sobeys vs Save-On) ship as a separate published surface with its own methodology document, different ToS profile, and weekly cadence
- Not provincial: No Quebec / Ontario / Atlantic / Prairie / BC decomposition. The StatsCan provincial CPI tables exist and a future cycle can incorporate them
- Not category-level within food: No dairy vs produce vs protein decomposition within this index. StatsCan publishes sub-component CPIs for these and a future version can incorporate
- Internal source basket not yet validated against StatsCan weights: The internal price-history aggregator currently uses the set of products the daily-collection pipeline tracks. The composition of that set does not yet attempt to mirror the StatsCan food-component basket weights. A future cycle that validates and re-weights the internal basket will be reflected in an updated base-weight entry for the internal source
- No imputation for missing months: If StatsCan or BoC have not published for a given period, that source contributes via the fallback sentinel + 5% effective weight — not via imputation
- Cache-only read path: The public endpoint reads from a cached snapshot. The refresh is operator-driven. A 404 response means the operator has not yet refreshed for that (period, basket); not that the underlying upstream data is missing
7. Refresh Cadence
| Source | Refresh trigger | Typical cadence |
|---|---|---|
| StatsCan CPI Food | Statistics Canada monthly CPI release | ~Third Tuesday of the following month |
| Bank of Canada CPI | BoC Valet update following StatsCan | Same day as StatsCan CPI release or shortly after |
| Internal price history | Daily collection pipeline | Daily (aggregated to the consumer's queried period) |
| Blended snapshot | Operator-run refresh command after upstream sources update | ≤ 7 days after StatsCan monthly publication; sooner if dispatched manually |
The recorded_at field on every snapshot timestamps when the blend was computed. A consumer reading the API can compute snapshot staleness directly.
8. Reproducibility — How to Recreate One Blended Value
A third-party reviewer should be able to reproduce a single blended value from the three raw upstream sources within 30 minutes using only:
- A web browser
- A simple spreadsheet (Excel, Google Sheets, or equivalent)
- Standard calculator-grade math
Step-by-step
- Pick a period. Choose a month in canonical grammar (e.g.,
2026-04) for which the published snapshot is available atcanadianfoodindex.ca/api/v1/inflation-index/series?period=2026-04&basket=food_combined - Pull the StatsCan reading. Navigate to Statistics Canada Table 18-10-0004-01. Filter to the food component for the chosen period. Record the value
- Pull the BoC reading. Navigate to Bank of Canada Valet Web Service, series V41690973. Filter to the chosen period. Record the value
- Pull the internal reading. Read the
valuefield at the pathper_source.internal_price_history.valuein the/seriesJSON response. (This is the transparent disclosure — the internal source is documented in this methodology and the per-product contributing data is available on request to peer reviewers) - Compute lag in days between each source's
freshness_timestampand the snapshot'srecorded_attimestamp - Compute effective weights for each source using the formula in section 3
- Compute the weighted average using the formula in section 3.4
- Compare to the published
blended_value. Should match to within rounding (4 decimal places of agreement)
Discrepancies between your reproduction and the published blended_value indicate either a bug in the blender (please report) or a stale snapshot (re-fetch).
9. Versions
- Version 1.0 (initial public methodology): Single national value per (period, basket) tuple. Stored as pre-computed
valuefield on each snapshot. - Version 1.1 (current — hybrid storage + multi-basket + X-13 SA): Stores raw monthly index levels per snapshot; derives views (basket × adjustment × window × period range) at request time. Adds three baskets (
food_combined,food_stores,food_restaurants), NSA + SA series per basket, and X-13ARIMA-SEATS SA derivation for sub-baskets where StatsCan does not publish SA cubes. See § 2.4. - Version 1.2 (planned): Per-retailer banner-level weekly snapshot. Separate methodology document; separate ToS profile; weekly cadence.
- Version 2.0 (planned): May add provincial decomposition, sub-category breakdowns within the national index, internal-basket re-weighting against StatsCan food-component weights, and additional non-food adjacent series (e.g., commodity input cost passthrough).
10. Contact + Peer Review
- Contact: hello@canadianfoodindex.ca
- Designated Privacy Officer: Privacy Office — privacy@canadianfoodindex.ca
- Methodology critique + suggestions: welcomed via the contact email. Material improvements will be acknowledged in subsequent version notes
Reproducibility commitment
Per section 8, any reader should be able to reproduce a published blended value from raw upstream sources within 30 minutes using a browser and a spreadsheet. The methodology constants used by the production blender (per-source base weights, fallback factor, freshness half-life, agreement variance scale) are documented in section 3 and re-derivable against the per-source contribution dictionary on every API response.
Interactive worked example
Move the controls below to see how the blended value and source-agreement scalar change. Export the resulting equation as LaTeX or Markdown for citation in your own document.
Source agreement: 0.9970 (3 of 3 fresh)
Export as LaTeX
\text{blended} = \frac{3.20 \cdot 0.401 + 2.80 \cdot 0.312 + 4.10 \cdot 0.195}{0.908} = 3.2563\%Export as Markdown
## Interactive worked example
| Source | Value | Lag (days) | Fallback | Effective weight |
|---|---|---|---|---|
| statscan_cpi_food | 3.20% | 5 | no | 0.4009 |
| bank_of_canada_cpi | 2.80% | 5 | no | 0.3118 |
| internal_price_history | 4.10% | 1 | no | 0.1954 |
**Blended value:** 3.2563%
**Source agreement:** 0.9970Read in plain language
Two cluster pages restate the methodology above in a more accessible register, indexed separately for AI Overview citation.
- How the Index is calculated — step-by-step walkthrough of the three sources, freshness decay, fallback factor, blended-value formula, and source agreement.
- The three baskets the Index publishes — food_combined (headline), food_stores (groceries), and food_restaurants (eating out): when to use each, plus how NSA and SA series differ.
- About the Index — editorial posture + independence + how decisions get made.
Looking for something else?
- For shoppers (in progress)
Why grocery prices changed this month, where prices are highest, and what the headline number means in real-life basket terms.
- For business (in progress)
Free B2B inflation index for CPG brands, retailers, and pricing analysts. JSON + CSV + OData; source attribution on every reading.
- For press (in progress)
Monthly Canadian food inflation readings with reproducible math and citable source attribution. Embed charts and quotes.
- For researchers (in progress)
Open methodology + raw monthly levels per basket. Dataset JSON-LD on every page; X-13ARIMA-SEATS seasonal adjustment derivation documented.
- For educators (in progress)
Index design walkthroughs for stats / data / journalism / economics classrooms. Three-baskets diagram and worked-example calculator.