Purpose
A canonical H3 cell set is an interchange format; no advertising platform
executes on H3 cells directly. Every platform imposes its own constraints
on what a targetable unit can look like, and a conversion that ignores them
produces a target list the platform will reject, silently truncate, or
silently re-interpret. This page enumerates the recurring constraint
classes and the mitigation for each, generically — see
data/platforms.yaml for named platform-class instances of these limits.
Source geometry and destination geometry
Source geometry is an h3_cell_set at whatever resolution the canonical
representation was built at. Destination geometry is whatever the target
platform accepts: platform_geo_id (native regions), point_radius
(circles), or occasionally a simplified polygon — never H3 cells
themselves, since no mainstream ad platform has native H3 support.
Exactness class
Conservative by design: the fitting process in this page trades resolution and target-count for platform executability, and every mitigation below either coarsens the footprint or drops a request outright rather than silently exceeding a hard platform limit.
The constraint classes
- Minimum radius
- A platform floor (commonly 1 km) below which a point-radius target cannot be executed. A fine H3 cell's inscribed or circumscribed radius can fall below this floor, making the cell un-executable as a circle.
- Maximum radius
- A ceiling (commonly tens of km) above which a single circle cannot be drawn, forcing large contiguous areas to split into multiple circles.
- Radius increments
- Platforms round a requested radius to a fixed increment (e.g. nearest 100 m), changing executed coverage from the requested value.
- Target-count limits
- A hard cap on distinct targeting entries per line item (hundreds to tens of thousands), which a fine H3 polyfill of a large area can exceed by orders of magnitude.
- Unsupported polygons
- Some platforms accept only circles and native IDs, forcing every polygon-derived target to be approximated by circles regardless of shape fidelity loss.
- Unsupported exclusions
- A platform without exclusion support cannot express include-A-minus-B; the exclusion is rejected or silently dropped, executing on the full inclusion set.
- Platform-native IDs only
- Some platforms accept only their own named geography IDs, requiring a maintained crosswalk from H3 with an accepted precision loss.
- Coordinate rounding
- Platforms may round submitted circle-center coordinates on ingest, shifting the executed center by up to the rounding's implied distance.
- Undocumented deduplication
- Some platforms silently merge or drop entries that overlap beyond an undocumented threshold, changing the executed count without warning.
- Optimized targeting expansion
- Some platforms auto-widen a small-audience target to hit a delivery goal, expanding the footprint beyond the submitted geometry unless opted out.
- Reporting at a coarser level
- Delivery and outcome reporting is often returned only at a coarser native geography (DMA, region), making the executed-vs-reported gap unmeasurable from reporting alone.
- Asynchronous boundary updates
- A platform's native geography IDs can be redefined on the platform's own schedule, unsynchronized with the boundary vintage used to build the crosswalk.
Containment rule and boundary behavior
Fitting an H3 cell set to a platform's constraints is, by construction, conservative-toward-executability, not conservative-toward-coverage: the process may coarsen resolution (increasing overreach) or drop unexecutable elements (reducing coverage) to satisfy a hard limit. Both outcomes must be reported — the fitted target list is not the same geography as the canonical H3 input, and the gap has a direction (coarsening overreaches; dropping underreaches) attributable to the constraint that forced it.
Resolution behavior
Resolution is the primary lever for fitting target-count limits: compacting
adjacent same-value cells (compact) and, where insufficient, coarsening
to a higher parent resolution reduces cell count at the cost of boundary
precision. For minimum-radius floors, coarsening is again the lever — a
coarser cell's circumscribed radius is larger and more likely to clear the
floor — while for maximum-radius ceilings the opposite applies: a
circumscribed circle exceeding the ceiling must split into smaller circles.
Units and CRS
EPSG:4326 for all geometry; radii in meters unless a platform's API
documents feet or another unit, in which case the conversion must convert
explicitly and record the platform's native unit in the ConversionRecord.
Algorithm
import { compact, uncompact } from "@/lib/h3/hierarchy";
import { circumscribedCircle } from "@/lib/h3/circles";
function fitToPlatform(cells: string[], platform: {
minRadius: number | null;
maxRadius: number | null;
maxTargets: number | null;
}) {
let working = compact(cells);
// Coarsen resolution stepwise until under maxTargets.
while (platform.maxTargets && working.length > platform.maxTargets) {
working = compact(coarsenOneLevel(working));
}
// Fit each remaining cell's circumscribed circle to min/max radius.
const circles = working.map((cell) => {
const { radiusMeters, center } = circumscribedCircle(cell);
const clamped = clampRadius(radiusMeters, platform.minRadius, platform.maxRadius);
return { center, radiusMeters: clamped };
});
return circles;
}
Parameters
The target platform's declared minRadius, maxRadius, radiusIncrements,
maxTargets, polygonSupport, exclusionSupport, adminIdSupport, and
nativeCellSupport — all sourced from a platform capability record such as
data/platforms.yaml, never assumed or hardcoded per campaign.
Outputs
A platform-executable target list (circles, native IDs, or a simplified
polygon set) alongside a record of every coarsening step, dropped
exclusion, and cell merged past its original boundary — the inputs needed
to compute overreach_ratio and coverage_ratio against the canonical set.
Quality metrics
overreach_ratio and coverage_ratio against the pre-fitting canonical
cell set, per the platform_limit_optimized profile
(conversion-profiles), whose stated guarantee
is that the result respects maxTargets and minRadius for the named
platform and whose stated tradeoff is that coarsening enlarges the
effective footprint.
Edge cases
minimum-radius and radius-increments interact: a cell coarsened just
enough to clear the minimum floor can still shift meaningfully once the
platform rounds to its nearest increment, so the final check must run
against the platform-quantized radius, not the pre-rounding one.
platform-native-ids-only and unsupported-exclusions both require a
fallback decided in advance — pre-subtracting an exclusion in cell space
before crosswalking to native IDs is the standard mitigation, flagged as
reported-vs-executed divergence regardless.
Assumptions and limitations
This page documents constraint classes generically; exact numeric limits
must be sourced from the platform's current API documentation via a
capability record, never from memory or this page — platform limits change
without notice, and a stale assumption here is a stale-boundaries-class
failure applied to platform capabilities rather than geographic ones.
