Ultimaps MCP

official

Turn data into map images: choropleth, category and pin maps of the world, countries, states, counties and ZIP codes.

What can you do with Ultimaps MCP?

  • Render choropleth maps — Ask for a map colored by numeric values, and get a classified PNG with legend and labels.
  • Highlight specific regions — Request a map with named states, counties, or ZIPs filled in custom colors, like "Where we operate."
  • Add location pins — Plot latitude/longitude markers with custom titles, colors, and label positions on any map.
  • Validate map data — Run a dry run to check which region keys match, get typo corrections, and see break values before rendering.
  • List available maps — Ask which of the 187 maps (countries, states, counties, ZIP areas) are available via list_maps.
  • Get region identifiers — Look up the exact keys or names for a map's regions to use in your render request via get_map_regions.

Documentation

Map Image API

Data in, map image out. One URL renders a choropleth, category or pin map of any country, state, county or ZIP area as a PNG. No account, no key, no map library in your stack.

https://api.ultimaps.com/v1/renders?spec=%7B%22mapId%22%3A%22united-states%22%2C%22regions%22%3A%7B%22US-CA%22%3A%22%231D4ED8%22%2C%22US-TX%22%3A%22%23F59E0B%22%2C%22New%20York%22%3A%22%2310B981%22%7D%2C%22title%22%3A%7B%22text%22%3A%22Where%20we%20operate%22%7D%2C%22style%22%3A%7B%22labels%22%3A%7B%22show%22%3Atrue%7D%7D%2C%22output%22%3A%7B%22width%22%3A1200%7D%7D

That is the whole request. The spec parameter is URL-encoded JSON, and the response is the image itself.

US map rendered by the Ultimaps API, every state labelled, with California, Texas and New York filled in

Rendered live by the URL on the left, cached for 24 hours.

Drops in anywhere

The URL returns the image, so it works in an <img> tag, a README, a Notion page or a Google Sheets cell.

GET or POST

GET takes every feature but caps the spec at 6KB, and it always renders keyless PNG up to 1600px. Send the same JSON to POST /v1/renders for a bigger payload, a key for a larger canvas, or a Pro key for SVG.

Editable afterwards

Every image carries a Link header that opens the render in Ultimaps Studio as a real map. Keyless renders open for anyone with the link. A keyed render opens only for someone signed in to that key's workspace.

Cookbook

Six complete requests. Every one is validated against the live request schema in CI, so you can copy them as they are, swap the mapId and the values, and go. Each image is the response the request next to it returned, watermark included, on the free keyless tier.

Highlight a few regions

The simplest useful request. You name regions and give each one a color. Everything else takes the map default.

{
  "mapId": "united-states",
  "regions": {
    "US-CA": "#1D4ED8",
    "US-TX": "#F59E0B",
    "New York": "#10B981"
  },
  "title": {
    "text": "Where we operate"
  },
  "style": {
    "labels": {
      "show": true
    }
  },
  "output": {
    "width": 1200
  }
}
curl https://api.ultimaps.com/v1/renders \
  -H "Content-Type: application/json" \
  -d '{
    "mapId": "united-states",
    "regions": {
      "US-CA": "#1D4ED8",
      "US-TX": "#F59E0B",
      "New York": "#10B981"
    },
    "title": {
      "text": "Where we operate"
    },
    "style": {
      "labels": {
        "show": true
      }
    },
    "output": {
      "width": 1200
    }
  }' \
  -o map.png

Map of the United States titled "Where we operate", with California blue, Texas orange and New York green, every other state in the theme default and labelled with its abbreviation

Map of the United States titled "Where we operate", with California blue, Texas orange and New York green, every other state in the theme default and labelled with its abbreviation

  • Region keys are flexible. "US-CA", "California" and "CA" all reach the same region.
  • Colors are hex strings. Regions you leave out keep the theme default.
  • "style.labels.show" prints every region name. There is no way to label only the regions you colored.

Open this render in a new tab

Choropleth from numbers

Give the API raw values and it picks the classes, the colors and the legend. This is the request most people want.

{
  "mapId": "united-states",
  "choropleth": {
    "values": {
      "California": 39.5,
      "Texas": 30.5,
      "Florida": 22.6,
      "New York": 19.6,
      "Pennsylvania": 13,
      "Illinois": 12.5,
      "Ohio": 11.8,
      "Georgia": 11,
      "North Carolina": 10.8,
      "Michigan": 10
    },
    "type": "groups",
    "palette": "blues",
    "classes": 5,
    "method": "quantile",
    "noDataColor": "#EEEEEE",
    "format": {
      "decimals": 1,
      "suffix": "M"
    }
  },
  "legend": {
    "position": "left"
  },
  "title": {
    "text": "Population by state, 2025"
  },
  "style": {
    "labels": {
      "show": true,
      "content": "value"
    }
  },
  "output": {
    "width": 1600,
    "scale": 1
  }
}
curl https://api.ultimaps.com/v1/renders \
  -H "Content-Type: application/json" \
  -d '{
    "mapId": "united-states",
    "choropleth": {
      "values": {
        "California": 39.5,
        "Texas": 30.5,
        "Florida": 22.6,
        "New York": 19.6,
        "Pennsylvania": 13,
        "Illinois": 12.5,
        "Ohio": 11.8,
        "Georgia": 11,
        "North Carolina": 10.8,
        "Michigan": 10
      },
      "type": "groups",
      "palette": "blues",
      "classes": 5,
      "method": "quantile",
      "noDataColor": "#EEEEEE",
      "format": {
        "decimals": 1,
        "suffix": "M"
      }
    },
    "legend": {
      "position": "left"
    },
    "title": {
      "text": "Population by state, 2025"
    },
    "style": {
      "labels": {
        "show": true,
        "content": "value"
      }
    },
    "output": {
      "width": 1600,
      "scale": 1
    }
  }' \
  -o map.png

Choropleth map of US state population in 2025, shaded across five blue quantile classes with the break labels in a legend and each value printed in millions on its state

Choropleth map of US state population in 2025, shaded across five blue quantile classes with the break labels in a legend and each value printed in millions on its state

  • Leave out "type", "classes" and "method" and the API detects them from your data.
  • "palette" takes any of the 26 built-in palettes. "noDataColor" paints regions your data does not cover.
  • "format" controls the break labels in the legend, not the image format.

Open this render in a new tab

Pins

Latitude and longitude markers. Pins compose with everything else, so you can drop them on a choropleth or on a plain map.

SVG output needs a Pro key. Drop "format" for PNG on any tier.

{
  "mapId": "united-states",
  "style": {
    "theme": "paper",
    "defaultRegionColor": "#F1F5F9"
  },
  "locations": [
    {
      "title": "Austin HQ",
      "lat": 30.2672,
      "lon": -97.7431,
      "color": "#1D4ED8"
    },
    {
      "title": "Denver",
      "lat": 39.7392,
      "lon": -104.9903,
      "labelPosition": "right"
    },
    {
      "title": "Seattle",
      "lat": 47.6062,
      "lon": -122.3321
    }
  ],
  "output": {
    "width": 1400,
    "format": "svg"
  }
}
curl https://api.ultimaps.com/v1/renders \
  -H "Content-Type: application/json" \
  -d '{
    "mapId": "united-states",
    "style": {
      "theme": "paper",
      "defaultRegionColor": "#F1F5F9"
    },
    "locations": [
      {
        "title": "Austin HQ",
        "lat": 30.2672,
        "lon": -97.7431,
        "color": "#1D4ED8"
      },
      {
        "title": "Denver",
        "lat": 39.7392,
        "lon": -104.9903,
        "labelPosition": "right"
      },
      {
        "title": "Seattle",
        "lat": 47.6062,
        "lon": -122.3321
      }
    ],
    "output": {
      "width": 1400,
      "format": "svg"
    }
  }' \
  -o map.svg

Map of the United States on a pale theme with labelled pins on Austin, Denver and Seattle, the Austin pin in blue and the other two in the default red

Shown as PNG — the request asks for SVG. Same map either way.

  • Each pin takes its own color, label side and label visibility.
  • Pins are placed by coordinates. The API does not geocode addresses.

SVG needs a Pro key. The keyless GET path returns PNG only.

Check a request before you render it

Dry run returns JSON instead of an image: which of your keys matched, which did not, what got corrected and what the breaks came out as. It costs no quota.

{
  "mapId": "united-states",
  "choropleth": {
    "values": {
      "Calfornia": 39.5,
      "Texas": 30.5,
      "Florida": 22.6,
      "Atlantis": 1
    }
  },
  "dryRun": true
}
curl https://api.ultimaps.com/v1/renders \
  -H "Content-Type: application/json" \
  -d '{
    "mapId": "united-states",
    "choropleth": {
      "values": {
        "Calfornia": 39.5,
        "Texas": 30.5,
        "Florida": 22.6,
        "Atlantis": 1
      }
    },
    "dryRun": true
  }'
  • The typo "Calfornia" comes back corrected to California. "Atlantis" comes back unmatched.
  • Use this while you wire up your data, then flip "dryRun" off.

Open the dry-run JSON this returns

Fail on bad keys instead of guessing

By default unmatched keys are skipped. Set "onUnmatched" to "error" and the API returns a 400 with per-key suggestions, which is what you want in a scheduled job.

{
  "mapId": "united-states",
  "choropleth": {
    "values": {
      "California": 39.5,
      "Texassss": 30.5,
      "Atlantis": 1
    }
  },
  "onUnmatched": "error"
}
curl https://api.ultimaps.com/v1/renders \
  -H "Content-Type: application/json" \
  -d '{
    "mapId": "united-states",
    "choropleth": {
      "values": {
        "California": 39.5,
        "Texassss": 30.5,
        "Atlantis": 1
      }
    },
    "onUnmatched": "error"
  }' \
  -o map.png
  • The 400 is an RFC 9457 problem document. Branch on "code", not on the message.

Open the 400 this returns

Full field reference, including all 26 palettes, the four break methods, themes, extra layers and number formatting: the API reference.

Maps you can render

187 maps, from world and continent maps down to US counties and ZIP code areas. The mapId is the map's slug on this site, and it never changes once it is published.

united-states-canada france-departments india europe canada united-states united-arab-emirates united-kingdom-counties world

Keys and limits

A key raises the rate limits and the canvas size. A Pro key removes the watermark and unlocks SVG. Create one in Studio under Workspace, then API. Keys are shown once.

curl https://api.ultimaps.com/v1/renders \
  -H "Authorization: Bearer $ULTIMAPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mapId": "united-states",
    "choropleth": {
      "values": {
        "California": 39.5,
        "Texas": 30.5,
        "Florida": 22.6,
        "New York": 19.6,
        "Pennsylvania": 13,
        "Illinois": 12.5,
        "Ohio": 11.8,
        "Georgia": 11,
        "North Carolina": 10.8,
        "Michigan": 10
      },
      "type": "groups",
      "palette": "blues",
      "classes": 5,
      "method": "quantile",
      "noDataColor": "#EEEEEE",
      "format": {
        "decimals": 1,
        "suffix": "M"
      }
    },
    "legend": {
      "position": "left"
    },
    "title": {
      "text": "Population by state, 2025"
    },
    "style": {
      "labels": {
        "show": true,
        "content": "value"
      }
    },
    "output": {
      "width": 1600,
      "scale": 1
    }
  }' \
  -o map.png
TierAuthFormatsAttributionCanvasRate limitMonthly
KeylessnonePNGfull watermark≤ 1600 px, scale 130/hour per IP, burst 5/minno monthly cap
Free keyBearer um_live_…PNGfull watermark≤ 1600 px, scale ≤ 210/min, 50/day500 renders
Pro keyBearer um_live_…PNG, SVGnone≤ 4000 px, scale ≤ 430/min, 1,000/day5,000 renders

Monthly quota is a billing state and returns 402, never retryable. Rate and concurrency limits return 429 with Retry-After. Dry runs never consume quota. Check GET /v1/usage for where you stand.

From Claude, Codex or any MCP client

Ask for a map in the chat and the image comes back in the conversation. @ultimaps/mcp is this API as MCP tools over stdio, with no account: render_map, list_maps and get_map_regions.

claude mcp add ultimaps -- npx -y @ultimaps/mcp
codex mcp add ultimaps -- npx -y @ultimaps/mcp

Clients that read a config file take the same two values. This is claude_desktop_config.json.

{
  "mcpServers": {
    "ultimaps": {
      "command": "npx",
      "args": ["-y", "@ultimaps/mcp"],
      "env": { "ULTIMAPS_API_KEY": "" }
    }
  }
}

Leave ULTIMAPS_API_KEY empty for the keyless tier, same limits as the table above, or fill it in for your plan's quota and output.

Not in v1

v1 renders images. It does not do any of this:

  • Publishing interactive or embeddable maps
  • PDF output
  • Geocoding addresses to coordinates
  • Reading back the geometry behind a map

If you need one of these, tell us which and we will let you know when it exists. What people ask for here is what we build next.

Reference

API reference

Every endpoint and field, live against the running API.

Error codes

Every code, its HTTP status, and whether to retry it.

openapi.json

OpenAPI 3.1 contract. Generate a client from it.

llms-full.txt

The whole API as one plain-text file for coding agents.

@ultimaps/mcp

The MCP server. Three tools, stdio, no account needed.

Frequently Asked Questions

Is there a choropleth API?

Yes, that is the main thing this API does. Post a set of region keys and numbers and you get back a classified, colored, legended map as a PNG. The API picks the break method, the class count and the palette from your data unless you set them yourself.

How do I generate a map image from a URL?

Put your request JSON in the spec query parameter of GET /v1/renders and the response is the PNG itself. That URL works in an img tag, a markdown image, a Notion image block or a Google Sheets IMAGE() formula, with no key and no account.

Can I use the map image API without an API key?

Yes. The keyless tier renders PNG up to 1600 by 1600 pixels at 30 renders per hour per IP, with an Ultimaps watermark. A key raises the limits, and a Pro key removes the watermark and adds SVG.

Is this a county map API? Can I get county boundaries out of it?

It renders county maps as images, including all 3,143 US counties, but it does not serve boundary geometry. If you need GeoJSON or shapefiles to process yourself, use Census TIGER or Natural Earth instead. This API returns pictures.

Does it geocode addresses?

No. Pins are placed by latitude and longitude, and region colors are matched by region key or name. Geocoding is a Studio feature, not an API one.

Is there an MCP server?

Yes. Install @ultimaps/mcp in Claude Code, Codex, Claude Desktop, Cursor, VS Code or any other MCP client and it exposes render_map, list_maps and get_map_regions over stdio. It runs on Node.js 20 or newer, needs no account, and reads ULTIMAPS_API_KEY when you set one.

Can I get SVG instead of PNG?

Yes, with a Pro key. Set output.format to svg. Keyless and free keys return PNG.

What happens if my region names do not match?

Keys are matched case-insensitively against region codes, titles, common aliases and normalized titles, so US-CA, California and CA all reach the same region, and unambiguous typos are corrected and reported. By default unmatched keys are skipped and reported in a response header. Set onUnmatched to error and the request fails with per-key suggestions instead.

How do I put a map in a GitHub README?

Use the keyless GET URL as a markdown image. GitHub proxies it through Camo, and because the API sends a 24 hour cache header the image refreshes daily rather than freezing.

Can I render a map server side?

Yes. Every render happens on our servers, so there is no browser, no headless Chrome and no map library in your stack. A single HTTP call returns the finished image.