Geometry Embed v1
Bring geometry into your application.
Pre-release quickstart and reference
Embed access and keys
Generate an embed key in Account settings with a Free account and register your exact host origins. Display and editing are currently included within operating limits. Availability is subject to change.
Use a publishable embed key restricted to the intended host origins and enabled capabilities. Authoring requires editing entitlement. A confidential server API key cannot authorize the picker.
Register exact origins such as https://your-app.example, with separate development and staging
origins as needed. Paths and wildcards are not accepted. HTTP is allowed only for localhost or loopback
development. Origin restrictions control browser integration; they do not authenticate arbitrary non-browser
callers.
Account access, any configured expiry, revocation and operation permissions are checked on each server operation. To rotate a key, issue a replacement, update your integration and then revoke the old key. The full key is shown only when issued. Signing in to this website does not replace an integration credential.
Need backend encode/decode as well? Obtain a separate confidential server key.
Embed the geometry picker
- Obtain a publishable embed key with the intended host origins and geometry access. Authoring also needs the key’s editing entitlement.
- Put the HTML below on your host page and replace
ISSUED_PUBLISHABLE_EMBED_KEY. Serve the host from a registered origin. - Keep stable application IDs for entries. Only confirmed changes should update your stored business data.
The example shows a photo vector, turbine point and windfarm area, with an application-owned list outside the iframe. It handles selection, errors, previews and confirmations. No SDK is required.
<iframe id="geometry-picker" title="Select asset geometry"
style="width:100%;height:600px;border:0"></iframe>
<p id="picker-status" role="status"></p>
<ul id="asset-list"></ul>
<script>
const frame = document.getElementById('geometry-picker');
const embedOrigin = "https://spatialglobe.com";
const key = 'ISSUED_PUBLISHABLE_EMBED_KEY';
const requestId = 'asset-map';
const records = new Map([{"id": "photo:001", "title": "DSC_0001.jpg", "srl": "p1!D6GX-USMO-AWUM-GIKX", "color": "#d946ef"}, {"id": "component:turbine-01", "title": "Turbine 01", "srl": "!D6GX-USMO-CTIL", "color": "#16a34a"}, {"id": "component:windfarm", "title": "Windfarm", "srl": "p1!D6GX-USMO-VE3K-KUBM-FKSP-EGSV", "color": "#2563eb"}].map(entry => [entry.id, entry]));
const errors = new Map(), accepted = new Set();
let instanceId = null, selectedId = null, loaded = false;
const status = document.getElementById('picker-status');
const send = command => frame.contentWindow.postMessage({
source: 'spatialglobe.picker', version: 1,
instanceId, requestId, ...command
}, embedOrigin);
function renderList() {
const list = document.getElementById('asset-list');
list.replaceChildren();
for (const entry of records.values()) {
const row = document.createElement('li');
const button = document.createElement('button');
button.type = 'button';
button.textContent = entry.title || entry.srl;
button.disabled = !loaded;
button.setAttribute('aria-pressed', String(entry.id === selectedId));
button.addEventListener('click', () => send({type:'select', entryId:entry.id}));
row.appendChild(button);
if (errors.has(entry.id)) {
const error = document.createElement('p');
error.textContent = errors.get(entry.id).message;
row.appendChild(error);
}
list.appendChild(row);
}
}
window.addEventListener('message', event => {
if (event.origin !== embedOrigin || event.source !== frame.contentWindow) return;
const m = event.data;
if (m?.source !== 'spatialglobe.picker' || m.version !== 1) return;
if (m.type === 'ready') {
if (m.instanceId === instanceId) return;
instanceId = m.instanceId;
loaded = false;
accepted.clear();
errors.clear();
send({type:'init', entries:[...records.values()], config:{ui:{list:false}}});
renderList();
return;
}
if (m.instanceId !== instanceId || m.requestId !== requestId) return;
if (m.type === 'loaded') loaded = true;
if (m.type === 'selection') selectedId = m.entryId;
if (m.type === 'preview') status.textContent = 'Unconfirmed geometry preview';
if (m.type === 'confirm') {
const operation = `${instanceId}:${m.operationId}`;
if (accepted.has(operation)) return;
accepted.add(operation);
records.set(m.entryId, m.entry);
errors.delete(m.entryId);
status.textContent = 'Geometry confirmed';
// Persist the entry in your backend here, with your own authorization.
}
if (m.type === 'error') {
if (m.entryId) errors.set(m.entryId, m.error);
status.textContent = m.error.message;
}
if (m.type === 'cancel') {
status.textContent = m.scope === 'session' ? 'Session closed' : 'Draft discarded';
if (m.scope === 'session') loaded = false;
}
renderList();
});
renderList(); // Install the listener before navigating the iframe.
frame.src = `${embedOrigin}/embed/geometry/${encodeURIComponent(key.split('.')[0])}/`
+ `?origin=${encodeURIComponent(location.origin)}#key=${encodeURIComponent(key)}`;
</script>
Install the message listener before assigning iframe.src. Verify both event.origin and
event.source, then the version, instance and request IDs. A new iframe instance gets a fresh instanceId;
initialize again after reload. The key is delivered in the URL fragment rather than a query parameter.
Entries, titles and colors
Each entry has id and a full public srl. Optional title and
color belong to that entry. IDs are opaque strings up to 128 characters, unique within the
instance, and returned unchanged. Duplicate SRLs with different IDs are allowed.
Titles are at most 160 characters. Without a title, the internal list shows the SRL and the map label shows its
geometry type. Colors use six-digit hex, such as #d946ef. Entries without a color receive different
available colors from the shared 18-color palette, which cycles when exhausted. Explicit colors may repeat.
The save icon confirms a draft to the host. Clear/close discards the draft and prepares the next permitted
geometry; it does not close the session. UI-created entries receive embed:<uuid> IDs. Map
them to your records when accepting a confirmation.
Configure the picker
init.config can only reduce the capability ceiling configured on the key. Omitted configuration or
{} requests the full implemented feature set allowed by that key. Display-only entitlement still
prevents authoring.
Each instance supports up to 1,000 entries, including failed entries. Set
maxEntries from 1 to 1000 on the key and/or host configuration to reduce that ceiling.
The iframe loads entries in packets of at most 100 and keeps the previous accepted dataset if a packet fails.
Each packet counts toward the key's request limits. Above 200 entries, the internal list uses 100-row pages
and map detail labels follow the inspected geometry; all accepted geometries remain on the map.
{}
{
"operations": [
"display"
],
"ui": {
"listManagement": false
}
}
{
"operations": [
"create"
]
}
{
"ui": {
"list": false
}
}
{
"geometries": {
"point": {
"precisions": [
12,
16
],
"parameters": {
"radius_m": {
"min": 0,
"max": 100
}
}
}
},
"regions": [
{
"center": [
11.575,
48.137
],
"radius_m": 5000
}
]
}
| Field | Contract |
|---|---|
operations |
Subset of display, create, edit. Empty array disables all. Create-only initialization needs entries:
[].
|
geometries |
Map of point, segment, route, rectangle, polygon or vector. Omitted includes all; a supplied map includes only its named kinds; empty map disables all. |
precisions |
Code lengths 12, 16, 20, 24, 28, intersected with per-kind support. |
| Per-kind options | operations, precisions, regions and parameter intervals using min, max or
both.
|
ui |
Boolean switches: search, srlInput, list, listManagement, info, geometry, parameters, views, measure. Default true. |
Per-kind precision choices: point 12/16; segment 16/20/24; route, rectangle and vector 16; polygon 16/20/24/28.
Parameter intervals use the physical parameter
names in the geometry reference; point constraints may also use elevation_storeys. They
check decoded, quantized values when present and do not require an optional value to exist.
Key and host operation, geometry and precision sets intersect. UI flags combine with AND. Parameter intervals intersect; contradictory intervals reject configuration. Hiding controls alone does not restrict the corresponding geometry operation. Search and SRL-input switches also gate those server operations.
Three list profiles
ui: {list:false}: your host website owns the visible list; rendering and confirmed results still work.ui: {list:true, listManagement:false}: an internal selection list without rename, color or delete controls.- Both true: transient list management, including the edit hand, sections, movement, colors, copying and delayed deletion with Undo.
Positions use WGS84 [longitude, latitude] in degrees. Physical distances and elevations use meters,
speeds use meters per second, and angles use degrees.
Region constraints
Root or per-kind regions accept one to four WGS84 circle regions: {"center":[11.575,48.137],"radius_m":5000,"scope":"geometry"}.
Radius is 0–500,000 meters. Alternatives in one list form a union; root, per-kind, key and host restrictions all
apply.
Default geometry scope checks supported decoded physical extent. Uncertifiable boundary cases are
denied. anchors scope checks only decoded anchor/control vertices. Nonzero displacement vectors
currently require anchors scope; full 3D vector containment is not supported. Search and camera navigation may
leave the region; geometry results must pass the constraints.
General polygon masks and political-boundary constraints are not configuration inputs. Long/extruded segments and unsupported render geometries report errors rather than being reduced to points.
Commands and events
Every message contains source: "spatialglobe.picker", version: 1,
instanceId, requestId and type. Before initialization, requestId is null.
The host supplies a nonempty requestId up to 100 characters. Optional host state is JSON up to 2,048 JavaScript
code units and is echoed on confirm/cancel; it grants no access rights.
| Direction | type | Fields and behavior |
|---|---|---|
| Picker → host | ready |
product=srl-geometry; capabilities with maxEntries, maxBytes, displayKinds, editableKinds, policy ceiling and persistence=false. |
| Host → picker | init |
entries; optional config, state and selectedId. One configuration per iframe instance. |
| Picker → host | loaded |
total, displayed, failedIds and effective policy. |
| Host → picker | select |
entryId; optional commandId (up to 100 characters). |
| Picker → host | selection |
entryId, entry, status, reason host/list/map and commandId. Failed entries include their error and do not move the camera. |
| Host → picker | create |
entry with fresh id and optional title/color; optional starting point position. Explicitly starts a fresh draft. |
| Host → picker | upsert |
entries and optional commandId; add new IDs or replace matching IDs without reload. |
| Host → picker | remove |
entryIds and optional commandId; remove session entries. Unknown IDs reject the command without partial removal. |
| Picker → host | updated |
action upsert/remove, commandId, entryIds and failedIds. |
| Picker → host | preview |
entryId, entry, result, operation create/update and operationId. Uncommitted. |
| Picker → host | confirm |
Same identity/result/operation fields, plus state. Deduplicate by (instanceId, operationId) before storing business changes. |
| Host ↔ picker | cancel |
Host cancels a draft, or closes an idle session. Picker returns scope entry/session, entryId, state and operationId for a draft. |
| Picker → host | error |
error with public code/message, recoverable=true, and entryId when tied to a failed supplied entry. |
| Picker → host | listchange |
Local management action update/remove/move/sections; entryId/title/color or sectionId/sections. These are UI notifications, not instructions to delete business records. |
send({type:'upsert', commandId:'refresh-turbine', entries:[{
id:'component:turbine-01', title:'Turbine 01',
srl:'!D6GX-USMO-CTIL', color:'#f97316'
}]});
// Wait for updated with the matching commandId before continuing.
send({type:'remove', commandId:'remove-photo', entryIds:['photo:001']});
// After the removal acknowledgment, start a new host-assigned entry.
send({type:'create', entry:{id:'component:new', title:'New component'}});
// Clear an open draft first; configuration changes require a reload.
Confirm or clear an open draft before selection or dataset changes. Updates are serialized. Existing IDs retain position, identity and section; new IDs append. Omitted color keeps an existing color; omitted/empty title clears its title.
Structural batch errors reject initialization or update. Invalid, unsupported or policy-denied SRLs fail individually and stay identifiable by host ID. Invalid replacements remove stale map geometry and can be repaired by later upsert. Your host list should show those per-entry errors; the internal list does so when enabled.
Picker results contain the public SRL, generation/link fields, geometry_kind, GeoJSON geometry, represented parameters and requested_parameters. Titles and colors accompany the entry identity and remain separate from the SRL code.
Limits and errors
| Boundary | Contract |
|---|---|
| Request body | 131,072 UTF-8 bytes per server request, including the signed policy. |
| Inventory | 1,000 session entries in packets of up to 100, including failures. Filter larger inventories at the host. Invalid or unsupported entries do not prevent the remaining entries from being displayed. |
| Usage counters | Shared minute/day quota per embed integration, with additional per-key ceilings, including compute and data operations. |
| Current defaults | 60/minute and 10,000/day, unless configured otherwise. |
| Session policy | Signed effective policy lasts one hour. Key-policy or authoring-entitlement changes require reload and initialization. |
Rate values are provisional operational defaults, not purchased allowances or an SLA. Authorized invalid
requests also consume quota. Application quotas are not a billing ledger. Responses use Cache-Control:
no-store.
Configuration failures use API.EMBED.INVALID_CONFIG; denied capabilities use API.EMBED.POLICY_DENIED.
Embed key/origin/entitlement denials return 403. Quota denial returns 429 with Retry-After: 60.
Host-facing errors arrive as versioned error events, with entry IDs where applicable.
Handle structural batch failures separately from per-entry errors. Keep failed entries visible in your host list with their IDs and allow correction or removal. See Commands and events.
Backend requests have a separate Server API quota and HTTP error contract.
Versions and availability
Use Geometry Embed v1 for display, selection and permitted authoring. The retired point-only picker is removed. The picker’s workbench transport is an internal UI interface.
Session handoff and confirmed edits do not create persistent Library entries. Your application remains responsible for saving records and business associations. Explicit customer Library saving, custom saved-entry metadata/sharing, proximity queries and automatic photo association are separate work.
Higher-volume paid plans and pricing have not been set. View plans or contact us about your requirements.