# How to Interact with GeoLibre Files Programmatically: 3 Methods Explained

> Learn to interact with GeoLibre files programmatically using 3 methods: Zustand store API, embed API, or FastAPI side-car. Integrate and manipulate geospatial data efficiently.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: how-to-guide
- Published: 2026-08-18

---

**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`](https://github.com/opengeos/GeoLibre/blob/main/.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`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/store.ts). This store holds all project state and exposes methods for loading, creating, and modifying [`.geolibre.json`](https://github.com/opengeos/GeoLibre/blob/main/.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`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/project.ts) | [`store.ts`](https://github.com/opengeos/GeoLibre/blob/main/store.ts) |
| `loadProject(project, path?, options?)` | Replaces store state with a `GeoLibreProject` object | [`store.ts`](https://github.com/opengeos/GeoLibre/blob/main/store.ts) |
| `addGeoJsonLayer(name, geojson, sourcePath?, beforeLayerId?)` | Adds vector layer from parsed GeoJSON | [`store.ts`](https://github.com/opengeos/GeoLibre/blob/main/store.ts) |
| `addTileLayer(name, options, beforeLayerId?)` | Adds raster or vector tile layer from URL template | [`store.ts`](https://github.com/opengeos/GeoLibre/blob/main/store.ts) |
| `setProjectPath(path)` / `setProjectName(name)` | Updates stored location or title | [`store.ts`](https://github.com/opengeos/GeoLibre/blob/main/store.ts) |
| `markSaved()` | Clears dirty flag after successful write | [`store.ts`](https://github.com/opengeos/GeoLibre/blob/main/store.ts) |

### Loading a Remote Project File

```typescript
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

```typescript
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

```typescript
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`](https://github.com/opengeos/GeoLibre/blob/main/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:

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

```

### Sending Commands from Parent Page

```html
<iframe id="geoLibreFrame" src="https://web.geolibre.app/"></iframe>

```

```javascript
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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/backend/geolibre_server/app/main.py) |
| `/project` | POST | Accepts `GeoLibreProject` payload and persists to path | [`backend/geolibre_server/app/main.py`](https://github.com/opengeos/GeoLibre/blob/main/backend/geolibre_server/app/main.py) |

### Python Client Example

```python
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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/.geolibre.json) file operations:

- **`ensureProjectFileName(name)`** — Appends [`.geolibre.json`](https://github.com/opengeos/GeoLibre/blob/main/.geolibre.json) extension if missing. Source: [`tests/file-names.test.ts`](https://github.com/opengeos/GeoLibre/blob/main/tests/file-names.test.ts)
- **`projectPathLabel(path)`** — Extracts human-readable label from full path or URL. Source: [`packages/core/src/store.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/store.ts) (line 331)
- **`isFetchableUrl(url)`** — Validates URL against security allow-list. Source: [`apps/geolibre-desktop/src/lib/embed-api.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/embed-api.ts) (line 420)

## Complete Interaction Workflow

The typical programmatic workflow follows five steps:

1. **Obtain** [`.geolibre.json`](https://github.com/opengeos/GeoLibre/blob/main/.geolibre.json) via download, side-car request, or file system read
2. **Parse** JSON into `GeoLibreProject` type (defined in [`packages/core/src/types.ts`](https://github.com/opengeos/GeoLibre/blob/main/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

- **Store API** ([`packages/core/src/store.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/store.ts)) provides direct TypeScript/JavaScript control for in-app scenarios
- **Embed API** ([`packages/embed/src/index.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/embed/src/index.ts)) enables cross-frame and desktop shell integration via postMessage
- **FastAPI side-car** ([`backend/geolibre_server/app/main.py`](https://github.com/opengeos/GeoLibre/blob/main/backend/geolibre_server/app/main.py)) offers HTTP endpoints for server-side operations
- All paths use the **same `GeoLibreProject` type** defined in [`packages/core/src/types.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/types.ts)
- **Validation helpers** ensure consistent file naming and URL security across environments

## Frequently Asked Questions

### What file format does GeoLibre use for projects?

GeoLibre uses **[`.geolibre.json`](https://github.com/opengeos/GeoLibre/blob/main/.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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/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.