US Retail Sales by NAICS
Monthly US retail and food-services sales by NAICS industry category, both seasonally adjusted and not adjusted, in millions of dollars, from the Census Bureau's Monthly Retail Trade Survey.
census_retail_sales - the dataset name to pass to the Obscura API.
What one row means
One month's total US retail or food-services sales for one NAICS industry category, on one seasonal-adjustment basis, in millions of dollars.
One row per (category_code, adjustment, occurred_on).
Point-in-time availability
Every Obscura dataset carries available_date: the calendar day the publisher made the row
available, day-of, with no session rounding. It is the one column a backtest filters on, and it means the
same thing on every dataset in the catalog.
For census_retail_sales: published: available_date is the day THAT MONTH'S figure first became public, measured per month rather than stamped from the current release. It is read from the real-time publication archive (ALFRED's vintage record for RSAFS, the headline series of this same Census release, so its vintage dates ARE this workbook's release dates): the vintage published in month M+1 carries reference month M, verified 2026-08-25 against three anchors - the 2001-06-13 vintage is newest-May-2001, 2001-07-13 is newest-June-2001, and 2026-08-14 is newest-July-2026, the last agreeing exactly with the Census release feed's own pubDate. That gives 302 of the 414 months a MEASURED publication day spanning 2001-05 to 2026-06. The 112 months before 2001-05 predate the archive, which opened on 2001-06-13 already holding them; those rows carry 2001-06-13, which is the earliest day they can be PROVEN to have been public - an upper bound, never presented as the true publication day, and in the safe direction because it is later than the truth and so cannot leak. A month newer than the archive carries the current edition's feed pubDate, which for that month is exact. A scalar release-lag rule was considered and rejected: across 324 measured vintages the lag from the reference month's end spreads over 9-12 business days with a tail to 23, so any fixed offset would be a schedule guess presented as a measurement. occurred_on is the first day of the reference month and is weeks earlier than available_date; it must never be used as the point-in-time basis.
Refresh cadence
Obscura refreshes census_retail_sales every weekday - the most frequent scheduled job that re-collects or re-exports it. This is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when a row became public is recorded per row in available_date.
Schema - 10 columns
The full public column list for census_retail_sales, with the meaning of every field. The same
schema is served unauthenticated at https://api.obscura.trade/v1/catalog/census_retail_sales.
| Column | Type | Description |
|---|---|---|
| category_code | text · not null | WHICH RETAIL CATEGORY, and the stable half of the key: the published NAICS code where the line has one (`441`, `4411,4412`, `44111`, `442299`), or a minted slug for the seven aggregate lines that do not (`total_retail_and_food_services`, `gafo`, …). Deliberately NOT the published label: `4522` and `45221` are both published as "Department stores", so a label key would merge two distinct series. Stored as TEXT because NAICS codes carry meaningful leading structure, several lines are comma-joined code pairs (`442,443`), and the aggregate slugs are not numbers at all. |
| adjustment | text · not null | WHICH SEASONAL BASIS: `not_adjusted` (sales as actually transacted) or `seasonally_adjusted` (Census's X-13 adjusted series). Both are published and they are different numbers, not a transform a consumer can apply - the adjusted block covers 38 categories against the unadjusted block's 64. **Summing across this column double-counts every sale.** |
| occurred_on | date · not null | THE MONTH THE SALES HAPPENED IN, as that month's first calendar day. The event date, weeks earlier than `available_date` - Census publishes a month's retail sales in the middle of the following month at the earliest. **Never filter or join point-in-time on this**; that is `available_date`. |
| naics_code | text | The NAICS code exactly as Census published it, or NULL on the seven aggregate lines that have none. Redundant with `category_code` on coded rows and carried anyway, because it is the column a consumer joins to an external NAICS classification - and because its NULLness is the honest signal that a row is an aggregate rather than an industry. |
| kind_of_business | text · not null | Census's published label for the category ("New car dealers", "Grocery stores", "Restaurants and other eating places"). Not unique - see `category_code` - so it is for display, never for joining. |
| sales_millions_usd | bigint | Total sales in MILLIONS OF US DOLLARS for this category, basis and month, as Census publishes it. NULL when the cell is not a published number - read `cell_status` to learn which kind of absence, rather than treating a NULL as a zero. |
| cell_status | text · not null | WHY `sales_millions_usd` is or is not populated, so a NULL is never ambiguous: `published` (a real figure), `suppressed` (Census printed `(S)` - the estimate exists but does not meet publication standards), or `not_available` (Census printed `(NA)` - the series does not cover this month at all, typically a category that started later than 1992). Measured across the full workbook on 2026-08-25: 683 `(S)` cells and 432 `(NA)` cells. Collapsing them into one NULL would make "we measured it and may not print it" and "this series does not exist here" indistinguishable. |
| estimate_vintage | text · not null | HOW SETTLED this figure is: `preliminary` for a month Census flagged `(p)` in the column header - the most recent month, still subject to revision - or `final` for a month carrying no flag. Census revises retail sales materially, so a consumer differencing a preliminary month against a final one is partly measuring the revision. |
| available_date | date · not null | PUBLIC-AVAILABILITY DATE - the day THIS MONTH'S figure first became readable. **The point-in-time column: filter and join on this, never on `occurred_on`.** Measured per month from the real-time publication archive, NOT stamped from whichever edition the collector happened to read. 302 of the 414 months (2001-05 onward) carry their true publication day. The 112 months before that predate the archive and carry `2001-06-13` - the earliest day they can be proven to have been public. Treat those as an upper bound: the figures were published in their own decade, and the bound only says we cannot measure exactly when. It is later than the truth, never earlier, so it can cost recall but can never leak. |
| source_release_date | date | Release day of the edition this row's CURRENT values were last read from. Census benchmarks restate history - the April 2025 benchmark removed nonemployers from every month back to 1992 - so a row keeps the `available_date` on which it first became knowable and updates this, and the two together say "known since X, last restated by the Y release". |
Access census_retail_sales
Two delivery paths, one identifier. Both require an Obscura account and an active subscription; the catalog entry and the schema above are public.
import obscura
client = obscura.Client("obs_live_…")
df = client.query(
dataset="census_retail_sales",
symbols=["NVDA", "AAPL"],
start="2024-01-01",
)
Create a free account Browse all 122 datasets
Frequently asked questions
What is in the census_retail_sales dataset?
Monthly US retail and food-services sales by NAICS industry category, both seasonally adjusted and not adjusted, in millions of dollars, from the Census Bureau's Monthly Retail Trade Survey. One month's total US retail or food-services sales for one NAICS industry category, on one seasonal-adjustment basis, in millions of dollars.
How do I avoid look-ahead bias with census_retail_sales?
Filter on census_retail_sales.available_date, the day the publisher made the row public. For this dataset that date is derived as follows - published: available_date is the day THAT MONTH'S figure first became public, measured per month rather than stamped from the current release. It is read from the real-time publication archive (ALFRED's vintage record for RSAFS, the headline series of this same Census release, so its vintage dates ARE this workbook's release dates): the vintage published in month M+1 carries reference month M, verified 2026-08-25 against three anchors - the 2001-06-13 vintage is newest-May-2001, 2001-07-13 is newest-June-2001, and 2026-08-14 is newest-July-2026, the last agreeing exactly with the Census release feed's own pubDate. That gives 302 of the 414 months a MEASURED publication day spanning 2001-05 to 2026-06. The 112 months before 2001-05 predate the archive, which opened on 2001-06-13 already holding them; those rows carry 2001-06-13, which is the earliest day they can be PROVEN to have been public - an upper bound, never presented as the true publication day, and in the safe direction because it is later than the truth and so cannot leak. A month newer than the archive carries the current edition's feed pubDate, which for that month is exact. A scalar release-lag rule was considered and rejected: across 324 measured vintages the lag from the reference month's end spreads over 9-12 business days with a tail to 23, so any fixed offset would be a schedule guess presented as a measurement. occurred_on is the first day of the reference month and is weeks earlier than available_date; it must never be used as the point-in-time basis. A query of the form WHERE available_date <= '<as-of date>' never sees a row before it existed.
In what formats can I get census_retail_sales?
As a Parquet bulk export (POST https://api.obscura.trade/v1/download) or as JSON from the typed query API (POST https://api.obscura.trade/v1/query), both with dataset="census_retail_sales". The column schema is public at https://api.obscura.trade/v1/catalog/census_retail_sales.
Can I filter census_retail_sales by company or symbol?
Yes. census_retail_sales carries naics_code, the column the API's symbols filter resolves against.
How often is census_retail_sales updated?
Obscura refreshes census_retail_sales on a every weekday schedule - that is the most frequent scheduled job that re-collects or re-exports the table. It is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when the publisher makes a row available is described by the availability rule above, and is recorded per row in available_date.