How to Interact with GeoLibre Files Programmatically: 3 Methods Explained

You can interact with GeoLibre project files programmatically via the front-end Zustand store API for in-app manipulation, the embed API for cross-frame communication, or the FastAPI side-car for server-side operations.

GeoLibre stores complete project state in .geolibre.json files—JSON documents containing layers, styles, view settings, legends, story-map chapters, and widgets. Whether you're building automation scripts, embedding maps in third-party applications, or creating custom workflows, understanding how to read and write these files programmatically unlocks the full potential of the open-source mapping platform. This guide covers three interaction patterns based on the actual source implementation in opengeos/GeoLibre.

Front-End Store API: Direct In-App Manipulation

The primary interface for programmatic interaction is the Zustand store defined in packages/core/src/store.ts. This store holds all project state and exposes methods for loading, creating, and modifying .geolibre.json content.

Core Store Methods for File Operations

Method Purpose Source Location
newProject(options?) Creates fresh project with defaults from packages/core/src/project.ts store.ts
loadProject(project, path?, options?) Replaces store state with a GeoLibreProject object store.ts
addGeoJsonLayer(name, geojson, sourcePath?, beforeLayerId?) Adds vector layer from parsed GeoJSON store.ts
addTileLayer(name, options, beforeLayerId?) Adds raster or vector tile layer from URL template store.ts
setProjectPath(path) / setProjectName(name) Updates stored location or title store.ts
markSaved() Clears dirty flag after successful write store.ts

Loading a Remote Project File

import { useAppStore } from "@geolibre/core";

async function loadFromUrl(url: string) {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`Failed to fetch ${url}`);
  
  const project = (await response.json()) as GeoLibreProject;
  
  useAppStore.getState().loadProject(project, url, { 
    rememberRecent: true 
  });
}

The rememberRecent: true option adds the file to the recent projects list in the UI.

Creating a New Project and Adding Layers

import { useAppStore } from "@geolibre/core";

const store = useAppStore.getState();

// Initialize clean project
store.newProject({ name: "My New Map" });

// Add GeoJSON layer from parsed data
const geojson = {
  type: "FeatureCollection",
  features: [
    { 
      type: "Feature", 
      geometry: { type: "Point", coordinates: [-122.4, 37.8] }, 
      properties: {} 
    },
  ],
};

store.addGeoJsonLayer("Points of Interest", geojson);

For raster sources, substitute store.addTileLayer() with appropriate URL template options.

Exporting Current Project to File

function exportCurrentProject() {
  const state = useAppStore.getState();
  
  const project: GeoLibreProject = {
    name: state.projectName,
    version: 1,
    layers: state.layers,
    // Include additional fields per GeoLibreProject schema (packages/core/src/types.ts)
  };
  
  const blob = new Blob(
    [JSON.stringify(project, null, 2)], 
    { type: "application/json" }
  );
  
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = `${state.projectName || "Untitled"}.geolibre.json`;
  a.click();
  URL.revokeObjectURL(url);
}

Embed API: Cross-Frame and Desktop Integration

When GeoLibre runs in an iframe or Tauri desktop shell, external applications communicate via postMessage commands defined in packages/embed/src/index.ts. This enables programmatic control without direct access to the store.

LoadProject Command Structure

The embed protocol defines command shapes as TypeScript types. The loadProject command accepts a URL string:

// From packages/embed/src/index.ts
type LoadProjectCommand = { 
  type: "loadProject"; 
  url: string 
};

Sending Commands from Parent Page

<iframe id="geoLibreFrame" src="https://web.geolibre.app/"></iframe>
const iframe = document.getElementById("geoLibreFrame");

// Load remote project file into embedded viewer
iframe.contentWindow.postMessage(
  { 
    type: "loadProject", 
    url: "https://example.com/maps/myMap.geolibre.json" 
  },
  "*"
);

// Handle errors from embed
window.addEventListener("message", e => {
  if (e.data?.type === "error") console.error(e.data.message);
});

Embed Validation and Routing

Before executing commands, GeoLibre validates URLs through isFetchableUrl in apps/geolibre-desktop/src/lib/embed-api.ts (line 420). This allow-list restricts loadProject to http(s) and root-relative URLs for security. Valid commands are delegated to useAppStore.loadProject() via apps/geolibre-desktop/src/hooks/useEmbedApi.ts.

FastAPI Side-Car: Server-Side Operations

The Python FastAPI backend (backend/geolibre_server) provides HTTP endpoints for scenarios requiring server-side file handling—conversions, validation, or multi-user coordination.

Available Endpoints

Endpoint Method Description Source
/project GET Retrieves project JSON by URL (local path or remote) backend/geolibre_server/app/main.py
/project POST Accepts GeoLibreProject payload and persists to path backend/geolibre_server/app/main.py

Python Client Example

import requests

BASE_URL = "http://127.0.0.1:8765"

# 1. Read project from local file via side-car

resp = requests.get(
    f"{BASE_URL}/project",
    params={"url": "/tmp/myMap.geolibre.json"}
)
project = resp.json()

# 2. Modify project structure

project["name"] = "Edited Map"

# 3. Persist modifications

requests.post(f"{BASE_URL}/project", json=project)

The side-car's project utilities in backend/geolibre_server/app/project.py handle file I/O and path resolution, making this pattern suitable for headless automation and CI/CD pipelines.

Utility Helpers for File Handling

Several convenience functions assist with .geolibre.json file operations:

Complete Interaction Workflow

The typical programmatic workflow follows five steps:

  1. Obtain .geolibre.json via download, side-car request, or file system read
  2. Parse JSON into GeoLibreProject type (defined in packages/core/src/types.ts)
  3. Load via useAppStore.loadProject(project, path?, { rememberRecent: true })
  4. Manipulate through store methods—layers, styles, view, widgets
  5. Export modified state to JSON or push to side-car for persistence

This pattern scales from browser-based React components to Python automation scripts without changing core semantics.

Summary

Frequently Asked Questions

What file format does GeoLibre use for projects?

GeoLibre uses .geolibre.json files—JSON documents containing complete project state including layers, styles, view configuration, legends, story-map chapters, and widgets. The schema is defined in TypeScript at packages/core/src/types.ts.

Can I load a GeoLibre project from a custom web application?

Yes. For iframe embeds, send a loadProject command via postMessage to the GeoLibre frame. For tighter integration, import @geolibre/core and call useAppStore.loadProject() directly after fetching and parsing the JSON file.

How do I validate a project file before loading it?

The side-car's POST /project endpoint performs server-side validation. Client-side, check the TypeScript GeoLibreProject interface from packages/core/src/types.ts—the store methods assume well-formed input and will throw if required fields are missing.

Is programmatic access available in the desktop application?

Yes. The Tauri-based desktop app exposes the embed API through apps/geolibre-desktop/src/hooks/useEmbedApi.ts, and the FastAPI side-car runs as a local HTTP server on port 8765, enabling external scripts to read and write project files even when the UI is headless.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →