Free check ·
Replace a Socrata rows.csv link without breaking your columns
Tyler Technologies removes Socrata's SODA1 API on December 16, 2026, and scripts that download /api/views/…/rows.csv?accessType=DOWNLOAD stop working. One public pipeline already reported HTTP 410 feature_deprecated in October. Paste your link to get a replacement that keeps the old column names and keeps numbers as numbers.
Check a dataset
No sign-in. Your browser asks the portal you name for its public column list and the first line of the old download. What you paste is not sent to CyberNative.
Without the column list, this page cannot build the name map. The replacement URL for this dataset is still:
The general helper below reads the column names itself when your code runs.
Dataset
Download from this URL instead
On the 12 datasets we downloaded in full (up to 368,102 rows), it returned every row, with raw values. Column names are API field names, so step 03 maps them back. Tyler documents this endpoint as needing an app token or sign-in. On October 9, 2026 it answered without one, so add your token now: send it as the X-App-Token header, as the snippets show.
The SODA2 alternative, and its 1,000-row default
Without $limit, /resource/…csv returns only the first 1,000 rows and gives no error. It also uses API field names and ISO dates.
Why not export.csv?
Code that rebuilds the old file
Old column names and order, numbers read as numbers, and dates rewritten in the old file's format. Step 04 lists every name.
Column names: query.csv to the old file
query.csv field | Old column | Type |
|---|
query.csv also adds :id, :version, :created_at and :updated_at. The snippets drop them.
What still differs from the old file
One salary, three downloads
Tyler's SODA3 guide maps the full download to export.csv. The same article says to use query.csv for machine processing. Here is one employee's annual salary from Chicago's salary dataset, downloaded each way on October 9, 2026:
| Endpoint | Header | Value | pandas reads |
|---|---|---|---|
rows.csvSODA1, being removed | Annual Salary | 165624.00 | number |
export.csvthe documented swap | Annual Salary | "$165,624.00" | text |
query.csvfor machine processing | annual_salary | "165624" | number, new name |
export.csv keeps the names and formats the numbers. query.csv keeps the numbers and renames the columns. The checker combines the two good halves.In a sample of 120 datasets drawn from the 1,000 most-viewed in Socrata's US catalog, export.csv turned at least one plain-number column into formatted text in 65. query.csv kept the numbers in all 120, but it renamed columns in 115. This is a popular-dataset sample from one run on October 9, 2026, executed by us and not independently reproduced.
No page needed: a general helper
This function does the core of the fix for any dataset. It reads the column list, downloads query.csv and renames the columns. Unlike the snippets above, it does not restore dates or integer types. Pass regions=True (in R, regions = TRUE) if your old file also had the region columns the portal adds from a location: San Francisco's files did, New York City's and Chicago's did not.
import json
import urllib.request
import pandas as pd
def read_socrata(portal, dataset, app_token=None, regions=False):
"""Read a Socrata dataset with its SODA1 column names and raw values.
regions=True keeps the ":@computed_region_" columns, for portals whose
old file had them.
"""
with urllib.request.urlopen(f"https://{portal}/api/views/{dataset}.json") as r:
cols = [c for c in json.load(r)["columns"]
if (not c["fieldName"].startswith(":")
or regions and c["fieldName"].startswith(":@computed_region_"))
and "hidden" not in (c.get("flags") or [])]
df = pd.read_csv(
f"https://{portal}/api/v3/views/{dataset}/query.csv",
storage_options={"X-App-Token": app_token} if app_token else None,
)
return df[[c["fieldName"] for c in cols]].rename(columns={c["fieldName"]: c["name"] for c in cols})
read_socrata <- function(portal, dataset, app_token = NULL, regions = FALSE) {
meta <- jsonlite::fromJSON(sprintf("https://%s/api/views/%s.json", portal, dataset))
cols <- meta$columns
hidden <- if (is.null(cols$flags)) FALSE else vapply(cols$flags, function(f) "hidden" %in% f, TRUE)
keep <- !startsWith(cols$fieldName, ":") |
(regions & startsWith(cols$fieldName, ":@computed_region_"))
cols <- cols[keep & !hidden, ]
path <- tempfile(fileext = ".csv")
download.file(sprintf("https://%s/api/v3/views/%s/query.csv", portal, dataset), path, quiet = TRUE,
headers = if (!is.null(app_token)) c("X-App-Token" = app_token))
df <- read.csv(path, check.names = FALSE)[cols$fieldName]
names(df) <- cols$name
df
}
How we checked this page
On October 9, 2026 we ran the page's pandas and R snippets on 17 public datasets from 12 portals: New York City, Chicago, the CDC, New York State, New York State Health, Washington State, Austin, Cambridge, Edmonton, the Los Angeles Controller, Colombia's national portal and San Francisco. We compared each result with the real SODA1 file, read by pandas.read_csv and base R's read.csv with default settings.
- Column names and order matched the old file in all 17, in both languages. That includes the region columns San Francisco's old files had and New York City's and Chicago's did not: the page reads the old file's first line while it still answers and follows it.
- On the 12 datasets we downloaded in full (up to 368,102 rows), row counts matched, every column the old file gave as numbers stayed numeric, and the values matched. The exceptions are columns the checker lists under step 05: rounding the old file applied, and location text.
- On the 5 largest, we compared the first 40 MB of each file. Names and pandas column types matched. Rows come back in a different order, so we did not compare values there.
pandas 3.0.6 and R 4.4.2. This was executed once by us and not independently reproduced.
Limits
- This works for public tables. Private datasets, filtered views and map or chart views are not covered.
- Once the old download stops answering, the page can no longer check which columns it had. It then keeps the portal's region columns in lines marked for deletion: delete them if your old file did not have them.
- Rows can come back in a different order. Sort them if your code relies on order.
- The export warning comes from each column's display format and its smallest and largest values. On the 120-dataset sample it flagged 290 of the 291 columns that broke there. It also flagged 22 that had not broken in the part of each file we compared.
- CyberNative is not affiliated with Tyler Technologies or Socrata. Their documentation is the authority on dates and endpoints: Deprecation Roadmap.