Developers usually encounter crime data through a simple product question: "Can we show neighborhood risk for this location?" The input might be a ZIP code, an address, a latitude and longitude, or a map viewport. A good crime score API should make those entry points predictable without forcing your team to reconcile inconsistent location records before building the experience.

CrimeScore's ZIP support is designed for that workflow. A ZIP code lookup gives you a broad area estimate when the user only has a 5-digit ZIP. A coordinate lookup gives you a more precise score for a point. The embedded map gives context when a user needs to inspect nearby block groups rather than read a single number.

Before your first request

Choose your organization in the API key dashboard and use its secret key. Set CRIMESCORE_API_KEY privately in your terminal or server environment. Do not put the key in frontend JavaScript, source control, or a chat prompt. Publishable cs_pub_ keys are for map embeds; REST requests use a secret cs_secret_ key in the x-api-key header.

The curl examples require curl 7.76 or newer. They use the production API and each successful call consumes one request from the key's organization. The example locations demonstrate the input format; inspect your actual response for coverage and current values.

1. Look up a ZIP code estimate

Send the five-digit ZIP as a string, preserving any leading zero. GET /v1/score?zip=10001 resolves a scored Census ZIP Code Tabulation Area, or ZCTA. It is a broad estimate for that area, not a score for every address inside it.

curl --fail-with-body --silent --show-error --get \
  "https://api.crimescore.io/v1/score" \
  --data-urlencode "zip=10001" \
  --header "x-api-key: $CRIMESCORE_API_KEY"

A successful ZIP response includes zcta, resolved.zip, safety_score, safety_grade, components, and data. The metadata includes model_version, census_vintage, and block_group_count. A ZIP without score coverage returns an error; it does not mean the score is zero.

2. Resolve a coordinate to its block group

When a user selects a property or point, send lat and lng together. Do not include zip in the same request. Coordinate lookup returns the containing Census block group's score, not a measurement of the individual property.

curl --fail-with-body --silent --show-error --get \
  "https://api.crimescore.io/v1/score" \
  --data-urlencode "lat=40.7128" \
  --data-urlencode "lng=-74.006" \
  --header "x-api-key: $CRIMESCORE_API_KEY"

Coordinate responses use a 12-digit geoid instead of zcta. Keep that identifier as a string. The resolved object includes the input coordinates, state abbreviation, and county FIPS code. If your input is an address, use the public GET /v1/geocode helper first and confirm the intended match before scoring its coordinates. Geocoding does not consume a score request.

3. Request contributor details when needed

/v1/score already includes component scores. Use /v1/score/details for the available contributor explanations. It accepts the same ZIP or coordinate input and an optional component: overall, violent_crime, property_crime, disorder, or frequency. Omitting the component selects overall.

curl --fail-with-body --silent --show-error --get \
  "https://api.crimescore.io/v1/score/details" \
  --data-urlencode "zip=10001" \
  --data-urlencode "component=property_crime" \
  --header "x-api-key: $CRIMESCORE_API_KEY"

Details are included on Starter and higher plans, and in evaluation access when that capability is enabled. A successful details call consumes a separate request. Contributors explain model associations, not causes. Compare a component across locations; different components use different benchmarks and should not be ranked against each other.

4. Make the request from a Node.js backend

Save this as crime-score.mjs and run node crime-score.mjs with Node.js 22 or newer and your environment variable configured. The example makes one request and keeps HTTP status and the API error code available to a caller. It does not retry automatically.

const apiKey = process.env.CRIMESCORE_API_KEY;
if (!apiKey) throw new Error("Set CRIMESCORE_API_KEY in your server environment");

const url = new URL("https://api.crimescore.io/v1/score");
url.search = new URLSearchParams({ zip: "10001" }).toString();

const response = await fetch(url, {
  headers: { "x-api-key": apiKey },
  signal: AbortSignal.timeout(15_000),
});
const result = await response.json().catch(() => null);

if (!response.ok) {
  const error = new Error(
    "CrimeScore request failed: " + response.status + " " +
    (result?.error ?? "HTTP_ERROR")
  );
  error.status = response.status;
  error.code = result?.error ?? "HTTP_ERROR";
  throw error;
}

console.log({
  geography: result.zcta ?? result.geoid,
  safetyScore: result.safety_score,
  grade: result.safety_grade,
  components: result.components,
  modelVersion: result.data.model_version,
  censusVintage: result.data.census_vintage,
});

To use coordinates, replace the URL parameters with new URLSearchParams({ lat: "40.7128", lng: "-74.006" }). In your application, handle a failed lookup as unavailable data rather than displaying a score of zero. See the authentication and error guide for the difference between access, quota, coverage, and rate-limit errors. A timeout can occur after a request is charged; check usage before retrying.

Fit the response into your product

  1. Accept a ZIP code for early search, lead forms, saved searches, or market pages.
  2. Use the ZIP code score response as a broad estimate and label it that way in the UI.
  3. When the user selects a property or exact point, call the coordinate endpoint for a block-group score.
  4. Add an embedded map where users benefit from seeing how nearby areas differ visually.

Keep the geography visible

The API intentionally uses different identifiers for different lookup modes. Coordinate requests return a geoid because they resolve to a Census block group. ZIP requests return zcta because they resolve to a Census ZIP Code Tabulation Area estimate. That distinction helps generated clients and human readers avoid mixing precise coordinate scores with broader ZIP code estimates.

A simple rule for product copy: call coordinate results "location scores" and ZIP results "ZIP code estimates." Explain the underlying Census ZCTA once where technical precision matters. Modeled Safety Scores use a 0–100 comparative scale, with higher values representing safer relative standing. They are not official crime rates or guarantees.

Embeds and public previews

CrimeScore supports public map previews and authenticated production embeds. Production embeds use publishable keys configured in the dashboard for domain controls and plan-specific behavior.

Use with your AI coding assistant

Give your assistant the documentation index and OpenAPI contract so it can use the actual routes and response fields. A useful starting prompt is:

Read https://crimescore.io/llms.txt and the linked OpenAPI contract. Build a server-side Node.js integration that accepts either a five-digit ZIP or latitude and longitude, uses CRIMESCORE_API_KEY from the environment, and handles non-2xx responses by HTTP status and API error code. Preserve the returned geography and model metadata. Do not request my secret key in chat or make live API calls without my approval.

If you want an assistant to query locations directly instead of writing an integration, follow the separate CrimeScore MCP setup guide.

Evaluate the integration

Start with the public ZIP lookup page to see the no-account map experience. Then open the API playground to compare ZIP code and coordinate response shapes with your own API key. If you are evaluating alternatives, the comparison pages explain how CrimeScore differs from public map sites and raw crime data APIs.

Creating an account is free and does not require payment. When evaluation access is available, the published offer is 25 credits for 30 days in your initial organization. Check the dashboard for your remaining allowance, expiry, and enabled capabilities. Use a small set of representative locations, inspect the returned geography, and read the coverage and data limitations before choosing a paid plan or Starter trial.