SkillAgentSearch skills...

Citysdk

Convenient JavaScript utilities for working with Census APIs: Statistics, Cartographic GeoJSON, lat/lng -> FIPS, and other niceties (written in ClojureScript)

Install / Use

/learn @uscensusbureau/Citysdk
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Breaking Change (November 2022)

Due to free Dynos - which were used to proxy CORS requests - being deprecated by Heroku, pre 2.3 versions of CitySDK will cease to work client-side.

Additionally, the migration to AWS has forced us to migrate core config files which cause breaks in server-side code in the near future

Please update to the latest version of CitySDK (2.3) to fix

CitySDK v2

Thank You's due to some very generous Clojurians:

  • @thheller (author of the shadow-cljs build tool)
  • @cgrand (author of the xforms library)
  • The Clojure community at large

Installation

npm install citysdk

V 2.3 Changes

Starting with v2.3.0, CitySDK ships as an ESM export

Migration:

// 2.2.x or below
const census = require('citysdk')
// 2.3.x or above
import census from 'citysdk'

The citysdk Function

CitySDK exports a single function, which takes two arguments:

  • The first is an options object with a set of key/value pair parameters (See "Parameters" below)
  • The second is a conventional (error, response) node-style callback, which will be called upon completion of the census function and applied to the response

Parameters

Brief overview of each argument parameter that can be passed into CitySDK

| Parameter | Type | Description | Geocodes | Stats | GeoJSON | GeoJSON with Stats | | --------------- | ----------- | ------------------------------------------------------------------ | :--------: | :-----: | :-------: | :------------------: | | vintage | int/str | The reference year (typically release year) of the data | ✔ | ✔ | ✔ | ✔ | | geoHierarchy | object | The geographic scope and hierarchical path to the data | ✔ | ✔ | ✔ | ✔ | | sourcePath | array | Refers to the Census product of interest | | ✔ | | ✔ | | values | array | For statistics, values request counts/estimates via variable IDs | | ✔ | | ✔ | | geoResolution | str | Resolution of GeoJSON ("20m", "5m", and "500k" available) | | | ✔ | ✔ | | predicates | object | Used as a filter available on some values | | ✔* | | ✔* | | statsKey | str | You may request a key for Census' statistics API here | | ✔** | | ✔** |

* : optional ** : optional for < 500 requests daily

Geocoding (latitude/longitude -> FIPS code)

With the exception of "microdata" statistics (not yet available via Census' API), all Census data is aggregated to geographic areas of different sizes. As such, all of Census' API's require a set of/unique geographic identifier(s) to return any data (AKA: FIPS). Given that these identifiers are not common knowledge, the CitySDK provides a way for the user to identify their geographic scope of interest using a geographic coordinate (lat + lng).

Under the hood, this functionality calls the TigerWeb Web Mapping Service with the lat & lng provided and pipes the resulting FIPS codes into your options argument with the appropriate GEOIDs for identifying your geographic area of interest.

For a list of geographies currently available for geocoding with this feature, see the [Geographies Available by Vintage] section below.

There are two ways to scope your geography using this functionality:

  1. Request a single geographic area
  2. Request all of a descendant geography-type of a coordinate-specified geographic area

Example: Request a single geographic area by coordinate

RETURN TYPE: JSON

You may pass a {"lat" : <float>, "lng" : <float>} object as the first and only value for the geoHierarchy key:

import census from 'citysdk'

census(
    {
        vintage: 2015, // required
        geoHierarchy: {
            // required
            county: {
                lat: 28.2639,
                lng: -80.7214,
            },
        },
    },
    (err, res) => console.log(res)
)

// result -> {"vintage":"2015","geoHierarchy":{"state":"12","county":"009"}}

Notice how the function prepends an additional geographic component ("state" : "12") to the options object. In order to fully qualify the geographic area (GEOID) associated with the county, the state is needed. In this example the fully qualified GEOID would be 12009 with the first two digits (12) qualifying the state and 009 qualifying the county within that state. This appropriate geographic hierarchy creation is handled by the function for you.

Example: Request all of a descendant geography-type within a coordinate-specified geographic area

RETURN TYPE: JSON

import census from 'citysdk'

census(
    {
        vintage: '2015', // required
        geoHierarchy: {
            // required
            state: {
                lat: 28.2639,
                lng: -80.7214,
            },
            county: '*', // <- syntax = "<descendant>" : "*"
        },
    },
    (err, res) => console.log(res)
)

// result -> {"vintage":"2015","geoHierarchy":{"state":"12","county":"*"}}

All Census-defined geographic areas are composed of Census "Blocks". Some of these composed areas - themselves - compose into higher-order areas. These nested relationships between certain geographic areas allows the Census data user to request all descendants of a particular type.

👀 Caveats

  1. Internally, the CitySDK converts the geoHierarchy object to an ordered set, so this part of your request object must be in descending hierarchical order from parent -> descendant. E.g. - in the above - an object that contained {"county" : "*", "state" : {"lat" <lat> "lng" <lng>}} will not work.
  2. In this example, we added a second geographic level to our geoHierarchy object ("county" : "*"). It is important to use the "*" expression signifying that you want all of the specified level of descendants within the geography for which you supply a coordinate. No other expression will work.
  3. For some wildcard ("*") geographies, the Census API can accept a skipped or "leapfrogged" wildcard. For example:
geoHierarchy: {
  state: "01",
  tract: "*"
}

However, the fully qualified geographic id requires an intermediary scope (in the above case county). You can tell when an intermediary scope has been skipped by checking the payload of the stats request who's URL is logged by CitySDK.

Another indicator that you might be hitting this issue is if you get back an empty features list in your GeoJSON:

{ type: 'FeatureCollection', features: [ ] }

The solution to this problem is to add the skipped scope as a null property, e.g.:

geoHierarchy: {
  state: "01",
  county: null, // <- leapfrog fix
  tract: "*"
}

Statistics

This parameter set will call the Census Statistics API and reformat the results with a couple highly requested features:

  • Census statistics are returned as a standard JSON object rather than the csv-like format of the "raw" API
  • Statistical values are translated into properly typed numbers (Integers and Floats instead of strings), whereas all values are returned as strings via the "raw" API
  • Annotation values (e.g., error codes) that are returned (e.g., American Community Survey error codes) in places where data would be expected are returned as strings (rather than numbers) to make differentiating them from values a simple type check.

There are two ways to request Census statistics using citysdk:

  1. Calling for values of estimates and other statistical values (required)
  2. Apply a filter by using predicates (optional)

For both of these options, a sourcePath needs to be supplied. This is the fully qualified path to the product. For more information about how to find the sourcePath to your product of interest, go to the [Developers' Microsite] and - in any of the examples of making a call - take the path between <vintage>/ and the ?get. For example, for American Community Survey 1-year you'll the first example (2017) shows:

https://api.census.gov/data/2017/acs/acs1?get=NAME,group(B01001)&for=us:1
                           └─┬─┘└───┬────┘
                         vintage sourcePath

The corresponding sourcePath for this endpoint is ["acs", "acs1"]

Example: get "values" by ID:

RETURN TYPE: JSON

census(
    {
        vintage: 2015, // required
        geoHierarchy: {
            // required
            county: {
                lat: 28.2639,
                lng: -80.7214,
           
View on GitHub
GitHub Stars1.0k
CategoryDevelopment
Updated4d ago
Forks183

Languages

Clojure

Security Score

95/100

Audited on Mar 25, 2026

No findings