Polyfence is in Early Access. APIs and limits may still change. Your feedback shapes what we build.

Skip to content
Defined once
{
  "id": "zn_7c4a1f",
  "name": "Felixstowe · Yard 8",
  "type": "polygon",
  "polygon": [ { "lat": 51.95303, "lng": 1.3253 }, …5 ]
}
Area14.3 ha
Perimeter1.76 km
Payload261 B
Precision1e-6°
Flutter SDKpf_load_zones()GET /v1/zones/device-config
IDLEawaiting a crossing--:--:--
pf-esp32c3-9d2ae0
mobileevent.type
devicepf_get_events()
server{"type": …}
One zone. Three runtimes. Same tick.
—
evaluating
Drag a corner past the device

The geofence layer

One geofence layer.
Everywhere your product runs.

Give your app a list of zones, circles or polygons, and get an event when a phone or device enters or leaves one. The same zones run in your mobile app, on your own hardware and on your server.

  • Flutter
  • React Native
  • Embedded C
  • REST API
  • CLI

MIT-licensed SDKs · Free during Early Access

What we keep

A crossing tells you which device, which zone, which way and when. Never the route in between.

Every event lands as one row. The location that triggered it is checked, then thrown away, unless you switch retention on.

Your event log (every row we keep)—
EventZone / deviceRecorded

Written to your account

device_idzone_idzone_nameevent_typeevent_timestamp

device_id is a name you give the device. Our firmware builds one from the chip family and three bytes of a hardware ID. Either way we never ask who is holding it.

Evaluated, then dropped

latlngaccuracy_m

Position retention is off by default. We see a device id. You see your customer.

What the cap limits

iOS gives your app twenty geofences. Not twenty per library. Twenty.

The operating system’s geofence budget is a wake-up service, not the detector. Polyfence hands it the nearest few and evaluates the rest itself, in your process, on every fix.

One app, one hundred zones (each cell is one zone)outlined = a slot the OS holds  ·  dashed = taken back on reboot  ·  solid = evaluated in your process
iOS region monitoringCLLocationManager · CLCircularRegion20of 100 · survives

The default is the ceiling: there is no headroom to hand out. Which twenty is your problem, and it changes as the user moves.

Android region monitoringPlay Services · GeofencingClient100 → 0after a reboot

These are registrations, not memory. Play Services drops every one of them on reboot.

Polyfence on-device evaluationGeofenceEngine · every fixall of themevery fix

Every zone, on every fix. Nothing was handed out, so nothing can be taken back.

Polyfence does register OS fences (up to twenty on iOS, fifty by default on Android), but only as a wake source, only while your app is backgrounded, and only if you switch it on. Detection never depends on them, which is why the Polyfence figures are the only ones unchanged across the break.

What it costs to watch

With intelligent mode on Android, standing still is two minutes and moving near a zone is five seconds.

“Saves battery” is a promise you cannot check. The sampling interval is not. It is a table of constants in the shipped config, and it moves by 24× depending on what the phone thinks you are doing.

One minute of wall clock (each mark is one GPS fix)updateStrategy · intelligent
0:000:150:300:451:00
Moving, within 500 m of a zone boundarynearZoneUpdateIntervalMs
5 s12 fixes
Moving, further than 500 m outmovingUpdateIntervalMs
10 s6 fixes
Moving, further than 500 m out, battery 20 % or underlowBatteryUpdateIntervalMs
30 s2 fixes
Stationary: no 50 m move in five minutesstationaryUpdateIntervalMs
next at 2:00 →
2 min1 fix
Further than 500 m out, battery 10 % or underpauseOnCriticalBattery
pausednone
Inside 500 m and moving, proximity wins outright: neither the low-battery interval nor the critical-battery pause applies that close to a boundary. Played once at 12× real time.

Until you ask for it, the strategy is continuous: a fix every ten seconds wherever you are and whatever you are doing. The intervals above are the library’s built-in values for intelligent mode. They apply on Android once intelligent mode is given its proximity, movement and battery settings; iOS trades accuracy and distance filter instead of a timer.

What it takes to start

From an empty file to your first event.

Flutter, React Native, embedded C, or REST. The shortest code that gets you a first event in each; platform setup is in each README.

Flutterpubspec.yaml
flutter pub add polyfence
12345678910111213
import 'package:polyfence/polyfence.dart';
await Polyfence.instance.initialize();
await Polyfence.instance.requestPermissions();
await Polyfence.instance.addZone(Zone.circle(
  id: 'depot-north',
  name: 'Depot North',
  center: PolyfenceLocation(latitude: 51.95724, longitude: 1.30962),
  radius: 230,
));
Polyfence.instance.onZoneEnter.listen((event) {
  print('Entered: ${event.zoneName}');
});
await Polyfence.instance.startTracking();
README §Getting Started 1–513 lines
Same circle in all 4: 51.95724, 1.30962 · r 230 mCounts measured from the panels, not asserted
There is a CLI too. npm i -g polyfence-cli lists, creates and exports zones from a terminal. It manages your account rather than shipping inside your product, so it answers a different question than the four above.

What it’s for

The verb never changes.

The thing moving is yours. The line is yours. What happens when they meet is the part we do.

A vancrossesa depot gateand dispatch knows.Fleet & delivery

A collarcrossesa paddock lineand the farm knows.Livestock & agriculture

A tagcrossesa fence lineand the site knows.Perimeter security

A carcrossesa low-emission zoneand the driver knows.Compliance zones

A shoppercrossesa shop doorwayand the shop knows.Retail, tourism & events

A kidcrossesthe school gateand a parent knows.Family & personal safety

six sentences · one verbone row in your event log, whichever line is yoursall six, and what each would take to build →

Prototyping on hardware? Reference boards for WiFi, USB, cellular and LoRa run the same engine. Browse reference boards →

Define once. Evaluate anywhere.

Free during Early Access. No credit card.