Skip to main content

Areas

An area limits a feed to a part of the world. It is a name and a list of places (a city, a county, a state, a country, anywhere in the world) and circles (a point and a radius). An item is in the area when it is in any of them.

Two processors, one area​

An area is used through two processors, each holding its own copy of the places:

  • Area match (area_match) decides by boundaries, with no AI. Its output match is match (inside the area), no_match (outside it) or unknown (the item has no known location).
  • Area relevance (area_relevance) is AI: it judges from the item's own text whether the item takes place in or is about the area. Its output is answer (yes or no) with a confidence.

An item with no known location is unknown to area match, so it is not in the area by place: a filter on match = "match" alone (or in_area without areaRelevance) leaves it out. With area relevance, that processor judges it from its text. To keep such items by place, write your own filter on match != "no_match".

Use them together in an include, as any of the two: the boundary decides what it can, and area relevance catches what boundaries miss, such as an event whose venue the map placed in a town of the same name elsewhere, or a story about the region that names no place inside it.

{
"any": [
{
"processor": "AREA_MATCH_ID",
"output": "match",
"op": "=",
"value": "match"
},
{
"processor": "AREA_RELEVANCE_ID",
"output": "answer",
"op": "=",
"value": "yes"
}
]
}

Our opt-in filters do this for you: in_area for event feeds, and news and creator_posts for news feeds, each taking areaMatch and, optionally, areaRelevance. A feed that should keep strictly to the boundaries leaves area relevance out.

Keep the two processors' places the same. We do not copy one to the other or check that they agree. If they differ, an item can be in the area by one and out of it by the other, and the any lets in what either says: the feed then covers both areas. When you change the places, change both.

Area processors run on events and news by default (itemTypes), so one area serves all your feeds.

How area match decides​

  • Events are matched by their venue when they have one: the event is in the area when its venue is inside one of the places or circles. An event with no venue that names a region is in the area when that region is one of the places or lies inside one, or overlaps a circle. See How geography decides what a feed carries.
  • News items are matched by the places they are about: one of them must lie inside the area. A story about a whole state or country does not match a county by place; it reaches the feed only through area relevance.

A region that only contains one of the area's places (a whole state around your county) is not in the area by place.

Places​

definition.area.places holds 1 to 50 entries, each one of:

  • A place by name: { "name": "Gaston County, North Carolina" }, with an optional level. The name is resolved when you write it: it resolves when exactly one place at that level has a full name starting with it (ignoring case). Gaston County and Gaston County, North Carolina both work when only one place matches.
  • A place by id: { "id": "mbx_…" }, the id of a place a response returned: a place of one of your areas, or a candidate from a refusal.
  • A circle: { "center": { "lat": 34.925, "lng": -81.025 }, "radiusKm": 15, "label": "Within 15 km of Rock Hill" }. The radius is above 0 and at most 500 km.
  • A place or circle as a response returned it, with its type: a place is kept by its id (its other fields are ignored) and a circle is read as written. So you can send a definition you read back unchanged.

Two entries that resolve to the same place are refused: the later one is a 422 AREA_PLACES_UNRESOLVED failure with no candidates, as is an id we did not issue (see When a name does not resolve).

Levels​

levelWhat it is
countryA country
regionA state, province or similar
districtThe default. A county in the United States
placeA city or town
localityA part of a city or town
neighborhoodA neighborhood

A name resolves only at its level. A city needs "level": "place"; without it, the name is looked up as a county.

Places in a response​

A response returns the area with each place resolved:

{
"name": "Charlotte metro",
"places": [
{
"type": "place",
"id": "mbx_WyJkWEp1T20xaWVIQnNZenBCVmtKdk4xRSIsImRpc3RyaWN0IiwiTWVja2xlbmJ1cmcgQ291bnR5LCBOb3J0aCBDYXJvbGluYSwgVW5pdGVkIFN0YXRlcyJd",
"name": "Mecklenburg County",
"level": "district",
"displayText": "Mecklenburg County, North Carolina, United States",
"geo": {
"center": { "lat": 35.247, "lng": -80.833 },
"bbox": [-81.058, 35.002, -80.55, 35.515]
}
},
{
"type": "circle",
"center": { "lat": 34.925, "lng": -81.025 },
"radiusKm": 15,
"label": "Within 15 km of Rock Hill"
}
]
}
FieldDescription
typeplace or circle
idThe place's stable id. Send { "id": … } to keep the place without resolving its name again
nameThe place's name
levelIts level
displayTextThe place's full name. It is longer than the displayText of a news item's about.places (Sterling Heights, MI)
geocenter (lat, lng) and bbox ([west, south, east, north]); each null when unknown

Changing an area's places​

PATCH /processors/{id} with the whole new definition (see Changing a processor). Send the places you keep as { "id": … } (or exactly as the processor's last response returned them), and new ones by name:

{
"name": "Charlotte metro",
"definition": {
"area": {
"name": "Charlotte metro",
"places": [
{
"id": "mbx_WyJkWEp1T20xaWVIQnNZenBCVmtKdk4xRSIsImRpc3RyaWN0IiwiTWVja2xlbmJ1cmcgQ291bnR5LCBOb3J0aCBDYXJvbGluYSwgVW5pdGVkIFN0YXRlcyJd"
},
{ "name": "Union County, North Carolina" }
]
}
}
}

The change makes a new version of the processor and applies going forward. Make the same change to the area's other processor.

When a name does not resolve​

A name that matches no place at its level, or several, is refused with 422 AREA_PLACES_UNRESOLVED. Nothing is saved. details.failures lists each failing entry by its index in places, with up to ten candidates: for an ambiguous name, the places at its level it could mean; for a name with no match at its level, what the search found at other levels. The same code, with candidates: [], refuses an entry that resolves to a place an earlier entry already named, and an id we did not issue or that is malformed. An id from a candidate list whose place can no longer be found lists the places now found at its level. In this example, two of the candidates are shown and their ids are shortened:

{
"success": false,
"error": {
"code": "AREA_PLACES_UNRESOLVED",
"message": "1 of the area's places did not resolve to exactly one place: \"Union County\". Send a candidate's `id` as `{ \"id\": … }`, or a more specific name.",
"details": {
"failures": [
{
"index": 1,
"name": "Union County",
"candidates": [
{
"id": "mbx_…",
"name": "Union County",
"level": "district",
"displayText": "Union County, North Carolina, United States"
},
{
"id": "mbx_…",
"name": "Union County",
"level": "district",
"displayText": "Union County, South Carolina, United States"
}
]
}
]
}
}
}

Send the candidate you mean back as { "id": … }, or a longer name such as Union County, North Carolina. If place search is unavailable, the request is a 503 SERVICE_UNAVAILABLE with a Retry-After header.

Place search limit​

A POST /processors or PATCH /processors/{id} that searches places counts against your organization's place-search limit of 30 requests a minute, once per request however many places it names. A request searches when it gives a place by name, or by an id none of your areas holds. One that searches nothing (no area, only circles, or only places your areas already hold, sent back by id) does not count, and neither does a request refused before any search (a taken name, an invalid body). Over the limit the request is a 429 RATE_LIMITED with a Retry-After header (seconds to wait); nothing is searched or saved. When the limit cannot be counted, the request is a 503 SERVICE_UNAVAILABLE with a Retry-After header.

Creating an area​

Create the area match, then (if you want it) the area relevance processor with the same places:

{
"template": "area_match",
"name": "Charlotte metro",
"definition": {
"area": {
"name": "Charlotte metro",
"places": [
{ "name": "Mecklenburg County, North Carolina" },
{ "name": "Gaston County, North Carolina" },
{ "name": "Rock Hill, South Carolina", "level": "place" }
]
}
}
}
{
"template": "area_relevance",
"name": "Charlotte metro (relevance)",
"definition": {
"area": {
"name": "Charlotte metro",
"places": [
{ "name": "Mecklenburg County, North Carolina" },
{ "name": "Gaston County, North Carolina" },
{ "name": "Rock Hill, South Carolina", "level": "place" }
]
}
}
}

Both go to POST /processors. Processor names are unique in your organization, so the two need different names. Once the first is created, you can send its resolved places' ids to the second instead of the names.