Skip to main content

Overview

Layers supports geographic filtering and sorting against any product attribute typed as geo. Once an attribute is geo-typed, products carrying that attribute can be:
  • Filtered to only those within a radius, polygon, or bounding box of an origin.
  • Sorted by distance from an origin (ascending or descending).
Use this to power experiences like “stores near me”, “products available in this delivery zone”, or “tours within the highlighted region on the map”. Layers includes geo values with the rest of your catalog data, so geo filters and distance sorting work across search and browse requests.

Configuring a geo attribute

A geo attribute is a catalog attribute that gets geographic data from a geo-typed product metafield or a field on a referenced metaobject.

Supported attribute code patterns

For metaobject-reference sources, each referenced metaobject’s named field contributes a geo point, so a product can have many points, such as all retail locations that carry it. Filters and sorts consider all of a product’s points: a product matches if any point matches, and distance sorting uses the closest point.

Automatic detection for JSON metafields

Shopify does not have a native “geo” metafield type, so coordinates are typically stored inside a json (or untyped) metafield. Layers samples these metafield values during catalog sync. If every non-empty sample parses as the same geometry type, Layers sets the attribute’s value type to geo automatically.
  • Detection runs on the base metafields.{namespace}.{key} code only. Metaobject-reference sources are typed from the metaobject field definition and don’t need sampling.
  • Every sampled value must parse as a recognized geo payload (see Accepted input shapes) and must share a single geometry type (point, polygon, or multipolygon). A mix of shapes leaves the attribute alone so you can decide how to model it.
  • Detection is one-way. Once an attribute has a specific value type (geo or anything else), Layers never reclassifies it. To change a value type, edit the attribute on the Attributes page.
  • The check runs when Layers first discovers a metafield attribute from your catalog. It also runs one time per store against existing json metafield attributes on the release that ships this behavior, so existing stores start populating geo values on their next product sync with no manual attribute edit.
If you would rather set the value type yourself, create the attribute manually and pick geo with the geometry type you want. The automatic check skips attributes that already have a value type.

Geometry types

Accepted input shapes

The ingestion pipeline normalizes several common shapes into canonical GeoJSON before storing:
GeoJSON coordinates are [longitude, latitude] — the reverse of conversational lat, lng order. The shorthand { lat, lng } form is provided as a convenience.

Polygon matching

When the source geometry on a product is itself a polygon, such as a delivery zone, the default behavior matches it when the filter polygon and product geometry overlap. This is useful for finding any zone that overlaps the search area. A stricter matching behavior requires the filter polygon to fully contain the product geometry. This is useful for finding zones entirely within the selected region. The matching behavior is determined by the attribute definition, so the semantics stay consistent across surfaces.

Geo filter operators

Three new operators extend the filter expression language. Each takes a single payload object inside the values array. All operators accept either lat/lng or latitude/longitude (and lon) on coordinate fields. Bounding boxes also accept northEast/southWest camelCase corners.

Radius units

geoRadius accepts radius with a unit of m (meters, default), km (kilometers), or mi (miles):
The legacy radius_meters (or radiusMeters) form is still accepted and always means meters. If a request provides both forms, they must resolve to the same distance or the request is rejected. The unit you send is echoed back on any pickup-location distances in the response. See Local pickup filtering.

Examples

Products within 5 km of a shopper’s location:
Products inside the visible map viewport:
Products whose delivery zone covers a hand-drawn region:

Validation

Geo operator payloads are validated before the query runs:
  • lat must be between -90 and 90; lng between -180 and 180.
  • radius (or radius_meters) must be greater than 0. unit must be m, km, or mi.
  • Polygon rings must be closed (first and last position equal) and contain at least 4 positions.
  • Unsupported geometry types (e.g. LineString) are rejected.
A geo filter against a non-geo attribute, a missing attribute, or a malformed payload matches zero products rather than erroring on the whole request.

Sort by distance

The geo_distance sort order ranks products by distance from a given origin against a geo-typed attribute.

Multi-point products

When a product has multiple geo points, such as one per retail location, distance sorting uses the closest point. A product carried at three stores sorts by the closest of the three.

Products without geo data

Products with no geo values for the geo attribute are placed in a separate tier that always sorts after all products with a distance, regardless of direction. This prevents missing-data products from polluting the top of the result set.

Pairing filters and sort

Filter and sort can target the same or different geo attributes. A common pattern is to filter by radius and sort by distance against the same attribute, so the result set contains every product within range, ordered from nearest to farthest:

Local pickup filtering

Filter products by the Shopify locations where a variant is in stock and local pickup is enabled. Layers resolves eligible pickup locations at request time from the store’s synced locations, so the filter always reflects current inventory and pickup availability without any per-product ingestion. Use this to power “available for pickup near me” experiences. A shopper sets a search origin, and Layers returns only products with at least one variant available for pickup within the radius. The response includes each matching location’s name, address, and distance so you can render pickup badges without a second request.

Filter operators

The variants.pickup_locations property accepts the following operators: Geo operators are capped at a 100 km radius. Requests over the cap return HTTP 422 during validation. If no pickup-enabled locations match the geo payload or supplied ids, the filter matches zero products. An empty notIn list matches every product.

Example

Facet display

When variants.pickup_locations is requested as a facet with retrieveFacetCount enabled, Layers returns a facetDisplay block describing each matching pickup location:
  • distance is measured to the location’s coordinates from the geoRadius origin, converted to the response unit, and rounded to 2 decimal places. When the filter does not include a geoRadius (for example, an in filter), distance is null and distanceUnit is still present.
  • distanceUnit follows the unit supplied on the filter. When no explicit unit is set, Layers picks mi for US, GB, LR, and MM (inferred from context.geo.country) and km everywhere else.
  • address is always present. Empty strings are normalized to null. Phone numbers are not exposed.
  • facetDisplay is omitted when empty. When non-empty, it is returned even if enrichFacetMetaobjects is false.

Requirements

  • Locations must be synced from Shopify with Local pickup enabled. Layers reads pickup settings, address, and coordinates from the standard location sync.
  • The variants.pickup_locations attribute is created automatically. It is filterable everywhere but is not exposed as a storefront facet until you enable it on the Attributes page.

Ingestion behavior

Geo values are extracted from products during the catalog sync that powers searchable data:
  • For a metafields.{ns}.{key} attribute, the metafield value itself is normalized as a geo value.
  • For a metafields.{ns}.{key}.{field} attribute, every metaobject reference (single or list) contributes a geo point when its named field holds a geometry.
  • Malformed payloads are silently skipped — a single bad metaobject does not block ingestion for the rest.
  • Layers records whether each geo value came from a metafield or metaobject and identifies the source metaobject when applicable. This makes per-product geo data inspectable.
Location coordinates are captured during the standard Shopify location sync and power local pickup filtering. Re-running a location export refreshes stale coordinates so the pickup filter stays accurate. No action is required to opt in.

Troubleshooting

A geo filter returns no products. Confirm the attribute is configured for geographic data and that the source metafield or metaobject field contains a recognized GeoJSON or { lat, lng } payload. Check the most recent catalog sync ran after the geo data was added. Distance sort puts unexpected products at the top. Products with no geo data sort last by design. If a clearly-far product appears first, verify the product’s geo points actually reflect the intended coordinates. For products with multiple points, distance is measured to the closest point, so a single incorrect coordinate can pull the product higher in results. Polygon filter matches too aggressively. The attribute’s matching behavior controls this. The default behavior allows overlapping geometries, while stricter matching requires the filter polygon to fully contain the product geometry. Coordinate ordering looks reversed. GeoJSON uses [lng, lat], not [lat, lng]. If you’re constructing GeoJSON by hand, double-check the order — using the shorthand { lat, lng } form avoids the mismatch entirely.

See also