Find your next real estate market in minutes, not months.
A pip-installable Python package that pulls public government data about every major US metro and city — population growth, job growth, wages, unemployment — and stores it locally in SQLite for analysis. Use it as a library, from the CLI, or build your own UI on top.
Install
pip install cityscope
Or with uv:
uv add cityscope
Python API
from cityscope import api
# Fetch data from public sources
api.fetch("census_population")
api.fetch("bls_employment", skip_laus=True)
# Query as a DataFrame
df = api.to_dataframe(metric="population_change_pct", geo_type="metro", year=2024)
print(df.sort_values("value", ascending=False).head(10))
# Or as a list of dicts
rows = api.query(metric="employment_change_pct", geo_type="metro", year=2024, limit=10)
for row in rows:
print(f"{row['name']}: {row['value']:+.1f}% job growth")
# Look up stats for a specific address
report = api.lookup("1600 Amphitheatre Pkwy, Mountain View, CA", auto_fetch=True)
print(f"Metro: {report.metro.name} — {report.metro.metrics}")
print(f"City: {report.city.name} — population {report.city.population:,}")
print(f"County: {report.county.name}")
# Configure (optional — works with defaults)
api.configure(db_path="my_data.db", min_population=100_000)
# Check what you have
api.status()
api.list_sources()
api.get_geographies(geo_type="metro", min_population=500_000)
CLI
# Fetch data
cityscope fetch census_population
cityscope fetch bls_employment --skip-laus
cityscope fetch --all
# Query
cityscope query -m population_change_pct -g metro -y 2024
cityscope query -m employment_change_pct -g metro -y 2024 -n 10
cityscope query -m avg_annual_pay -y 2024 -n 15
# Look up stats for an address
cityscope lookup "1600 Amphitheatre Pkwy, Mountain View, CA"
cityscope lookup "123 Main St, Austin, TX" --auto-fetch
# Info
cityscope sources
cityscope status
Commands
| Command | Description |
|---|---|
fetch <source> |
Pull data from a source (census_population, bls_employment) |
fetch --all |
Pull from all sources |
query |
Query stored data (-m, -g, -y, --min-pop, -n) |
lookup <address> |
Look up stats for a US address (metro + city + county) |
sources |
List available data sources |
status |
Show fetched data summary |
init-config |
Generate default config/settings.yaml |
Address Lookup
The lookup command geocodes a US address (via the free Census Geocoder) and returns stats for the enclosing metro, city, and county:
cityscope lookup "1600 Amphitheatre Pkwy, Mountain View, CA" --auto-fetch
With --auto-fetch, cityscope will fall back to fetching missing data from source APIs on-the-fly (useful for addresses in counties or smaller cities not covered by the default 200k+ metro/city fetch). Results are cached in the local DB.
Global flags: -v (verbose logging), -c PATH (custom config file).
Fetch Flags
| Flag | Description |
|---|---|
--vintage YEAR |
Override Census vintage year |
--min-pop N |
Override population filter (default: 200,000) |
--skip-laus |
Skip unemployment rate (avoids BLS API daily limit) |
What Data You Get
370+ metros and cities (200k+ population), each tracked across 9 metrics over 5 years (2020–2024):
| Metric | Source | Description |
|---|---|---|
population |
Census PEP/ACS | Total population |
population_change_pct |
Census PEP/ACS | Year-over-year population growth % |
employment |
BLS QCEW | Total nonfarm jobs |
employment_change_pct |
BLS QCEW | Year-over-year job growth % |
avg_annual_pay |
BLS QCEW | Average annual pay ($) |
avg_weekly_wage |
BLS QCEW | Average weekly wage ($) |
unemployment_rate |
BLS LAUS | Annual avg unemployment rate (%) |
All data is free, public domain, pulled directly from federal APIs.
Configuration
Optional — everything works with defaults. For higher API limits:
# config/settings.yaml
census:
api_key: null # Free: https://api.census.gov/data/key_signup.html
bls:
api_key: null # Free: https://data.bls.gov/registrationEngine/
storage:
db_path: data/cityscope.db
pipeline:
min_population: 200000
Or configure programmatically:
api.configure(census_api_key="your_key", bls_api_key="your_key")
Architecture
Census API ──┐ ┌── Python API (cityscope.api)
├── Pipeline ── SQLite DB ──┤
BLS QCEW ──┘ (fetch) └── CLI (cityscope)
Data flows: Source → Pipeline → SQLite → API/CLI/your code.
Adding Data Sources
Each source is a self-contained class with @SourceRegistry.register:
from cityscope.core.registry import SourceRegistry
from cityscope.core.source import DataSource
from cityscope.core.models import FetchResult
@SourceRegistry.register
class MySource(DataSource):
source_id = "my_source"
name = "My Data Source"
description = "What it provides"
def fetch(self, **kwargs) -> FetchResult:
...
Add the import to src/cityscope/sources/__init__.py — it auto-registers in CLI, API, and pipeline.
Dashboard
For a visual dashboard, see urban-research-ui.
Roadmap
- Rent data (HUD Fair Market Rents, Zillow ZORI)
- Home price index (FHFA HPI)
- Crime stats (FBI Crime Data Explorer)
- School quality (NCES)
- Walkability (EPA Smart Location Database)
- Migration flows (IRS SOI county-to-county)
- Neighborhood-level data (Census tract)
- Composite scoring engine
See data_sources.md for research on 50+ public data sources.
Contributing
Pull requests welcome. The easiest way to contribute is adding a new data source — the plugin architecture makes it straightforward.
License
MIT
Built with Claude Code (Claude Opus 4.6).
Metadata
Release files for cityscope 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cityscope-0.4.0.tar.gz | 117.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cityscope-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 157.2 kB
Release files / cityscope-0.4.0.tar.gz
| Download URL | cityscope-0.4.0.tar.gz |
|---|---|
| Size | 117.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
40d60c1f79e168ddb7c177b878aefe896877cef5b18a0c34a3323ef5bba2b3bf
|
|
BLAKE2b-256 checksum How to use checksums |
11d5ef3a78796655befd7487a7b3d27ff4bdd96a6d704af6ac8a7fc12353e12d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 4, 2026.
Transparency logRelease files / cityscope-0.4.0-py3-none-any.whl
| Download URL | cityscope-0.4.0-py3-none-any.whl |
|---|---|
| Size | 39.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2c4e1292702ccd7c79588356228cf43b095f47a914e10d7a8d35ebe38fb3b83a
|
|
BLAKE2b-256 checksum How to use checksums |
00576cebc45bea5b92d4c2b0ff5c1571aa90c4e298321fd93b5d15d3c3e398c8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 4, 2026.
Transparency log