Skip to main content
Frames give the map its work areas and the data recorded on them. Load them before the map appears and save them on the device to work without signal. The map never touches the network itself: panning, drawing, showing and hiding work areas never wait on a connection and never spend the key’s budget. Everything on this page is the SDK making the same calls this site documents. The request and response contract is the API reference; this page is which of those calls the SDK makes, and when.

Which API calls the SDK makes

The SDK makes exactly three kinds of request, all on the frames service. It never looks frames up by state, LGA, ward or box.

Get your key

Create an API key in your LOCI dashboard under Developers → New key: pick a scope and an expiry, and copy the secret, which is shown once. See Authentication for the full story, and Scopes for what each preset reaches.
A key is read-only, acts for one organisation, and expires. Every device that uses the same key shares one rate-limit budget — see cost.

Initialise the SDK

Call Loci.initialize once, for example in Application.onCreate. Read the key from your own secure storage. After that, Loci.frames is the object every example here uses. Calling it again replaces the key; Loci.dispose() releases the SDK, and Loci.isInitialized says whether it is ready.
initialise
Every call returns at once and reports to its callback on the main thread with a LociFramesOutcome: Success with the value, or Failure with a LociFramesError. See Errors and events.

Two ways to give the map its work areas

Work areas come from boundaries you hold (Work areas) or from frames you load. Load frames before the map appears, for example when the user opens a project — not from a tap or a camera callback.

Find a frame

If you do not hold frame ids, ask for the frame under a coordinate or under one of your work areas. Both return the frame’s id, outline and box.
frameAtLocation and frameFromWorkArea
A point outside the grid fails with LociFramesErrorCode.NOT_FOUND. LociWorkArea.fromBbox(bbox, id) and LociWorkArea.fromFrame(frame) build a work area from a box or a frame.

Preload your frames

loadFrames returns the frames as work areas and the recorded shapes as layers. Pass both to the map.
load, then show
On a LociMapView set the same two values as properties:
show them on the view
Each frame is a work area with the frame id as its id; its data is under properties["frames"], by layer id. Frames start hidden — the user turns them on in the work-area dialog, or you call controller.showWorkArea(id). A frame follows every work-area rule, including geofencing.

What you get back

A LociFramesResult has these properties:
Recorded shapes in datasets are returned once and are not stored. After a pack load the view-only layers are empty: load from the cloud again or pass the features you keep.

Packs

A pack saves frames on the device under an id you choose, for example ward-7, so they load without signal. Ids use 1 to 64 letters, digits, _ or -. This is the only place LOCI stores data: a pack holds frame outlines, layer definitions and baseline values, encrypted and readable only on this device. It never holds features — the shapes users recorded on a frame, and the entries your app passes in, are not stored. Pass your features each time.
save, load, refresh, list, delete
What a pack stores: frame id, outline and bounding box; layer definitions and baseline values, except layers you hid (Hidden layers); and the creation time, the organisation and the optional maximum age. Packs are kept out of Android backups and need Android 6.0 (API 23); below that, pack methods fail with LociFramesPackError.STORAGE_FAILED. A pack is never refreshed automatically — call refreshPack. Expiry. Pass maxAgeSeconds to savePack or refreshPack. After that long the pack is expired, not deleted, and loadPack fails with LociFramesPackError.EXPIRED. LociFramesSource.PACK_FIRST treats an expired pack like a missing one and goes to the service; refreshPack works on it. With no maxAgeSeconds a pack never expires, and a refresh without it keeps the pack’s own.

Hidden layers

Keep a layer off the device, such as internal notes, by passing its id as hiddenLayerIds to loadFrames, savePack, loadPack or refreshPack. A hidden layer is not returned and is not stored in packs.
hide a layer

Source: cloud or pack

loadFrames reads from the service by default. Set source to read a pack.
pack first
To save frames, call savePack.

Errors and events

A failed call reports LociFramesOutcome.Failure with one of four errors. Branch on the case and its code, not on the message. None of them carries your key.
handle a failure

Events

Listen for things worth showing the user. addListener returns a function that stops listening.
listen
Retries. A 429 waits its Retry-After and is retried up to three times. A server error or dropped connection is retried once. Final codes are not retried. A failed fetch returns no partial result and does not change a pack.

Rate limits and cost

Rate limits apply per key and per organisation, so devices sharing a key share one limit. Load frames in your prepare step, not in a loop. Read retryAfterSeconds on a RATE_LIMITED error rather than any number here, because the numbers can change — the full detail is in Limits.
Keys expire, and a key stops working when the person who created it leaves the organisation. A phone offline for weeks may find its key dead — but pack data already on the device stays readable.