DemographIQ Docs

Shapefile Enrichment API

Enrich geographic data with census demographics using area-weighted calculations

Shapefile Enrichment API

The shapefile enrichment feature allows you to submit geographic data (shapes and points) and receive enriched census demographic information for the surrounding neighborhood.

Status: Production Ready
Performance: 7,092 geometries processed in 15 seconds
Important: Returns full census values (not area-weighted) representing neighborhood characteristics

Overview

This API endpoint enriches your geographic data with U.S. Census demographics, providing neighborhood-level characteristics for your areas of interest:

  • Returns full census block group values (not proportional to area)
  • Uses population-weighted aggregation when multiple census areas intersect
  • Handles points by buffering them into areas
  • Groups related parcels for aggregate analysis
  • Falls back to nearest census area if no intersection found

Quick Start

Authentication

First, obtain a JWT token:

TOKEN=$(curl -X POST http://api.localhost:8008/auth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=your_user&password=your_pass" \
  -s | jq -r .access_token)

Make a Request

curl -X POST http://api.localhost:8008/api/v1/shapefiles/enrich \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "shapes": [{
      "key": "parcel_123",
      "aggr_group": "ranch_A",
      "geometry": {
        "type": "Polygon",
        "coordinates": [[[-97.74, 30.26], [-97.74, 30.27], [-97.73, 30.27], [-97.73, 30.26], [-97.74, 30.26]]]
      }
    }],
    "census_metrics": {
      "geo_population": "B01003001",
      "geo_median_hhi": "B19013001"
    },
    "calculated_metrics": {
      "geo_population_density": "geo_population / geo_census_area_sq_miles"
    }
  }'

API Reference

Endpoint

POST /api/v1/shapefiles/enrich

Request Schema

{
  shapes?: Array<{
    key: string                    // Unique identifier
    aggr_group?: string           // Optional grouping key
    geometry: GeoJSON.Polygon     // GeoJSON polygon
  }>,
  points?: Array<{
    key: string                   // Unique identifier
    aggr_group?: string          // Optional grouping key
    latitude: number
    longitude: number
    buffer_meters: number        // Buffer radius for point
  }>,
  census_metrics: {
    [alias: string]: string      // e.g., "geo_population": "B01003001"
  },
  calculated_metrics?: {
    [alias: string]: string      // e.g., "density": "population / area"
  },
  year?: string,                 // Default: "2022"
  sumlevel?: string,             // Default: "150" (block groups)
  component?: string             // Default: "00"
}

Response Schema

{
  success: boolean,
  enriched_count: number,
  results: {
    [group_key: string]: {
      parcel_count: number,
      parcel_keys: string[],
      census_areas: string[],
      census_area_count: number,
      geo_census_area_sq_miles: number,
      metrics: {
        [metric_name: string]: number
      }
    }
  },
  warnings?: string[]
}

Key Features

Neighborhood Characteristics

The API returns full census values representing the neighborhood characteristics around your area of interest. When a shape overlaps multiple census blocks:

  • Count metrics (population, housing units): Population-weighted average
  • Median metrics (income, home value): Population-weighted median
  • Density metrics: Automatically calculated using total area

For example, a small house parcel will receive the full median income of its census block group (e.g., $60,000), not a tiny fraction based on its area.

Dynamic Metrics

Request any census table/column by specifying the census variable code:

Common MetricsCensus CodeDescription
PopulationB01003001Total population
Median IncomeB19013001Median household income
Housing UnitsB25001001Total housing units
Median Home ValueB25077001Median home value

Group Aggregation

Multiple parcels can be aggregated by providing the same aggr_group value. The API will:

  • Combine all parcels in the group
  • Calculate area-weighted metrics for the entire group
  • Return one result per group

Calculated Metrics

Create derived metrics using formulas:

"calculated_metrics": {
  "population_density": "geo_population / geo_census_area_sq_miles",
  "occupancy_rate": "(geo_occupied_units / geo_housing_units) * 100"
}

Performance

Dataset SizeResponse TimeThroughput
12 geometries~1 second12/sec
7,092 geometries14.96 seconds474/sec

Best Practices

  1. Batch Requests: Send multiple geometries in a single request for better performance
  2. Use Groups: Aggregate related parcels to reduce response size
  3. Limit Size: For datasets over 10,000 geometries, consider splitting into multiple requests
  4. Handle Negatives: Census special values (negative numbers) indicate missing data
  5. Focus on Density: For land valuation, population and housing density metrics are more meaningful than raw counts
  6. Understand Values: Results represent neighborhood characteristics, not proportional values for your specific area

Troubleshooting

Common Issues

401 Unauthorized

  • Ensure you have a valid JWT token
  • Check token expiration

Request Timeout

  • Consider reducing the number of geometries per request
  • Check if the census database connection is active

Empty Results

  • Verify your geometries are within the United States
  • Check the year/sumlevel parameters match available census data

Development Testing

For development, use the test endpoint without authentication:

POST /api/v1/shapefiles/test-internal

Example: Texas Land Pricing Integration

Here's a complete example for enriching multiple parcels:

import requests
import json
 
# Prepare the request
parcels = [
    {
        "key": "parcel_001",
        "aggr_group": "ranch_north",
        "geometry": {
            "type": "Polygon",
            "coordinates": [[...]]  # Your coordinates
        }
    },
    # Add more parcels...
]
 
request_data = {
    "shapes": parcels,
    "census_metrics": {
        "geo_population": "B01003001",
        "geo_median_hhi": "B19013001",
        "geo_housing_units": "B25001001"
    },
    "calculated_metrics": {
        "geo_population_density": "geo_population / geo_census_area_sq_miles"
    }
}
 
# Make the request
response = requests.post(
    "http://api.localhost:8008/api/v1/shapefiles/enrich",
    headers={
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    },
    json=request_data
)
 
# Process results
if response.status_code == 200:
    data = response.json()
    for group_key, metrics in data["results"].items():
        print(f"Group: {group_key}")
        print(f"  Population: {metrics['metrics']['geo_population']}")
        print(f"  Median Income: ${metrics['metrics']['geo_median_hhi']}")

On this page