Building Spatial Anchors With ARCore Geospatial API for Persistent Navigation

Augmented Reality
Date:November 12, 2026
Topic:
Building Spatial Anchors With ARCore Geospatial API for Persistent Navigation
⏱ 3 min read

Your phone knows where it is within a meter. That's GPS. But your AR app needs to know where it is within a centimeter, and which way it's facing, so a virtual arrow stays glued to a real street corner when you walk around the block. That's the ARCore Geospatial API, and it changes persistent AR from a demo trick into a shipping feature.

Why GPS Isn't Enough

Standard GNSS gives you a latitude, longitude, and a radius of uncertainty. In urban canyons, that radius balloons to 10–20 meters. ARCore's Visual Positioning System (VPS) matches live camera frames against Google's Street View imagery to produce a pose — position plus orientation — with sub-meter accuracy. The Geospatial API wraps VPS into a familiar anchor workflow: you create a GeospatialAnchor at a WGS84 coordinate, and the runtime keeps it locked to the real world across sessions, devices, and app restarts.

Core Concepts: Anchors, Terrain, and Rooftops

Three anchor types cover most navigation scenarios:

Anchor TypeUse CaseAccuracy Note
WGS84 AnchorStreet-level POIs, building entrancesBest where VPS coverage exists
Terrain AnchorParks, plazas, open areasSnaps to ground mesh; no VPS needed
Rooftop AnchorRooftop decks, helipads, solar arraysUses 3D building models; watch for occlusion
💡
TipAlways check GeospatialPose.accuracyHorizontalMeters before committing UI. Values under 1.0m are solid for pedestrian nav; above 3.0m, fall back to screen-space hints.

Implementation Walkthrough

kotlin
val session = Session(context)
val config = Config(session).apply {
    geospatialMode = Config.GeospatialMode.ENABLED
    streams.add(StreamType.GEOSPATIAL_POSE)
}
session.configure(config)

// Create anchor at known lat/lng/altitude
val earth = session.earth
val anchor = earth.createAnchor(latitude, longitude, altitude, quaternion)

// Later: resolve pose for rendering
val pose = earth.cameraGeospatialPose
if (pose.horizontalAccuracy < 1.0) {
    renderNavigationArrow(pose)
}

Key steps: enable GEOSPATIAL_POSE stream, request ACCESS_FINE_LOCATION, and handle EarthState.ENABLED callbacks. The Earth object is your gateway — it surfaces cameraGeospatialPose every frame and lets you create or resolve anchors by coordinate.

Handling VPS Gaps

VPS coverage isn't universal. Indoor, underground, or newly built areas fall back to fused sensor pose (IMU + GPS). Design for degradation: show a transparency pulse on anchors when accuracy drops, and switch to relative ARCore local anchors for short-range guidance until VPS recovers. Persist the last known good GeospatialPose to SharedPreferences so cold starts resume near the correct spot.

"

The map is not the territory, but a VPS-anchored arrow gets you closer than a blue dot ever could.

— ARCore Team, Google I/O 2026

Multi-Device Persistence

Anchors created on one device resolve on another because they're tied to geographic coordinates, not local feature maps. Store anchor payloads (lat, lng, altitude, quaternion, metadata) in your backend. On app launch, fetch nearby anchors, batch-create them via Earth.createAnchorAsync, and attach your 3D assets. This enables shared navigation layers — think campus wayfinding or mall directories — without each user re-scanning the environment.

⚠️
WarningAltitude is WGS84 ellipsoid height, not MSL. Convert using Geoid models (EGM96/EGM2008) if your source data is orthometric. A 20m altitude error puts your anchor on the wrong floor.

Performance & Battery

VPS localization runs a lightweight CNN on device. Expect 5–8% CPU on modern Snapdragon/Google Tensor chips. Throttle camera frame requests when the user isn't moving (detect via ActivityRecognition API). Cache Street View tiles for offline fallback — ARCore downloads them automatically, but you can pre-warm high-traffic zones via the Geospatial API's prefetch hints.


✦

Ship It Checklist

1. Verify VPS coverage in your target areas using the ARCore Geospatial Coverage Map. 2. Implement accuracy gating — hide anchors when horizontalAccuracy > 3m. 3. Persist anchor metadata server-side for cross-device sync. 4. Test altitude conversions with real devices on rooftops and basements. 5. Add a calibration UX: let users tap to nudge anchor position, then save the delta. 6. Monitor EarthState transitions in analytics to catch coverage blind spots. Start with a single-city pilot, measure anchor resolve latency (target < 500ms), then scale.

Share𝕏 Twitterin LinkedInin Whatsapp