The spatial studio for stories,
briefings and live dashboards.
People don't share shapefiles. They share stories, slides and dashboards. Spatly is the layer between raw GIS data and human attention: one project, one map, four publishable experiences, fed by live data and driven by your agents over MCP.
Basemap © OpenFreeMap · OpenMapTiles · data © OpenStreetMap contributors
One map, one dataset, one theme. Four ways to be read.
A Spatly project holds layers, styles, live bindings and beats once. Publish the same project as a scroll story for the public, a slide briefing for the board, a live wall for operations, and an insight card for the website, without re-drawing a single layer. The four frames below are screenshots of published templates.

Scroll a narrative; the map answers.
Sticky map, chapter column, camera choreography tweened against scroll progress.
For Journalists, researchers, NGOs, city comms
Explore stories
Brief a room with a map that moves.
16:9 slides on the same beats, presenter mode with notes, laser and next-slide peek.
For Consultants, planners, executives
Explore slides
Watch the ground change, live.
Linked widgets, extent filters, as-of stamps, stale states and an actions graph you can read.
For Logistics, climate, public safety, field ops
Explore dashboards
Ship one spatial fact into any page.
A designed card with a mini map, KPIs and one line of text, opening into the full workspace.
For Product teams, analysts, anyone who embeds
Explore insightsThree templates, embedded on this page with the same script tag you would use.
Nothing below is a picture. Each frame is a published Spatly surface loaded through /embed.js: a live insight card polling a REST source, a linked dashboard over 34,936 power plants, and a scroll story. Copy any of them into your workspace and take it apart.
Each frame reports spatly:ready when its map is up, and the badge in the frame's footer turns live when the message arrives. Embeds resize themselves through spatly:resize.
One editor for all four surfaces. The preview is the real viewer.
Scenes on the left, the published viewer in the middle, the inspector on the right. Move the map and press Save beat; drag a layer, a widget or a mark from the Library; switch story → slides → dashboard → insight without leaving the project. These are screenshots of the product, not mock-ups.


Dashboard grid. 24 columns, real drag and drop, widgets bound to metrics that recompute for the viewport.

Slides canvas. 16:9 frames over the map, one beat per slide, presenter notes on the rail.

Layer style editor. Classification, ramps, size and height targets, and labels, all compiled to MapLibre paint.

Actions graph. “When this widget emits that, filter, fly or flash these”. One inspector, no modal tabs.

⌘K palette. Search commands, blocks, layers and beats from the keyboard.

Insight container. Collapsed card and expanded drawer designed as two layouts on the same beat.
Save the map state once. Every surface replays it.
A Beat is pure target state: where the camera is, which layers are visible at what opacity, which annotations are on, what time it is. Stories, slides, dashboards and insights don't own their own map logic. They reference beats and decide only how to get there: fly, ease, jump, or tween against scroll.
- Move the map, press Save beat. Duplicate and nudge. Interpolate between two beats at any progress from 0 to 1.
- Convert a story to slides (chapter → slide) and back, because they were never different objects.
- Every beat has a deep link (#ch=3, ?beat=). Agents create beats through the same API you use.
- Camera
- Layer states
- Annotations
- Time
- Story chapter
- Slide
- Dashboard bookmark
- Insight expanded state
Dashboards and insights are never a screenshot.
Every live binding carries a refresh interval, a cache, a last-success time and an error surface. Widgets show an as-of stamp; when a source falls behind, the card goes hatched, visibly stale rather than silently wrong. Stories and slides can freeze a snapshot or stay live, per layer.
The whole dashboard, folded into one card you can put anywhere.
Collapsed: a designed card with a mini map, two to four KPIs and one sentence. Expanded: the full workspace with filters and an explorable map. Same data, same beat, two layouts. Drop it on a dashboard, into a story chapter, on your marketing site or inside your own app via SDK.
This one is real: filter by category, click a site, open and close it. Nothing here is a screenshot.
50% of monitored nodes on time. 2 delayed, 1 closed. Rail delays concentrate on the Asian side.
Your agent gets the same studio you do.
Spatly ships an official MCP server. Point Claude, Cursor, Copilot or ChatGPT at your workspace and they can describe layers, query features inside a bbox, save beats, write chapters and publish, all through the same REST API and the same permission model. Read tools on every plan; write tools scoped by token.
{
"mcpServers": {
"spatly": {
"command": "npx",
"args": ["-y", "@spatly/mcp"],
"env": { "SPATLY_TOKEN": "spk_…" }
}
}
}
# Remote (streamable HTTP), no install
URL https://spatly.io/mcp
Header Authorization: Bearer spk_…
Agent-safe by construction: every list paginates, query_features is capped by the workspace budget (500 rows per call, 60 calls per minute by default) and can require a bbox. An agent cannot dump a dataset by accident.
- You
Create a 6-chapter story from this GeoJSON. It's the Kahramanmaraş aftershock sequence. Lead with the two mainshocks, end on the 20 Feb Hatay event.
- create_project{ name: "Kahramanmaraş 2023", basemapId: "noir" } → prj_8f2
- describe_layer4,812 features · point · fields: mag, depth_km, time (datetime) · bbox 35.9,36.2 → 39.1,38.6
- query_featureswhere mag ≥ 6 order by time · limit 20 → 5 rows (M7.8 01:17, M7.5 10:24, M6.7, M6.4 Hatay …)
Five events above M6. I'll open on the M7.8 at Pazarcık with the fault trace, cut to the M7.5 nine hours later, then step the time filter week by week and close on Hatay. Writing chapters.
- create_story_chapter × 6each with a beat: camera + layerStates.filter (time ≤ chapter end) + highlight (mag ≥ 6) + transition fly 1.6 s
- publish_share_linkvisibility: unlisted → https://spatly.io/s/kmr-2023-aft
Done. Six chapters, unlisted link, 4,812 features stay live from the USGS feed. Chapter 4 could use a pull quote. Want me to draft one from the viewport stats?
An original visual language. Sold, not decorated.
128 UI icons, 22 map markers, atlas ornaments, chart marks and animated live affordances, all on one 24px grid with a 1.5px stroke and one recurring survey tick. Marks follow your theme tokens, load into MapLibre as SDF images, and export as an SVG sprite + React components for your own apps.
Power users bring PostGIS habits. Beginners bring a spreadsheet.
Drop a file and Spatly ingests it into PostGIS, samples field stats for ramps and categories, and serves it as GeoJSON or vector tiles depending on size. A CSV with an address column gets geocoded on the way in. Every source keeps its refresh policy, cache and health.
- ≤ 5k features
- GeoJSON endpoint
- > 5k features
- ST_AsMVT tiles
- ≤ 500 rows
- auto-geocode

Real surfaces, on open data, running live.
Free to publish. Pay when you outgrow three projects.
All four surfaces, MCP and embeds on every plan. Paid plans add room, members, a custom domain and remove the badge.
- 3 projects · 10 datasets
- 250 MB storage · 2 live bindings
- 1 member
- Custom domain
- Remove “Made with Spatly”
- 50 projects · 200 datasets
- 10 GB storage · 25 live bindings
- 3 members
- Custom domain
- Remove “Made with Spatly”
- 500 projects · 2000 datasets
- 100 GB storage · 200 live bindings
- 25 members
- Custom domain
- Remove “Made with Spatly”
Drop a GeoJSON. Get a story in ten minutes.
Wire a live KPI without code. Embed the insight anywhere. Let your agent do it for you.
41.0082°N 28.9784°E · z 11.3 · ⟂ 0°



