# iso.me Maps for Obsidian
Render interactive Leaflet maps inline in Obsidian notes from [iso.me](https://apps.apple.com/us/app/iso-me/id6761960794) exports and compatible location-tracking formats.
The plugin registers an Obsidian Markdown code block named `iso-me`. Add a fenced block to any note, point it at one or more export files in your vault, and the plugin renders visits, routes, outliers, stats, and optional interactive filters.
---
## Quick start
1. Install and enable **iso.me Maps** in Obsidian.
2. Export data from the iso.me iOS app. JSON combined exports are the easiest starting point.
3. Put the export in your vault, for example `exports/iso.me-2026-05-04.json`.
4. Add this to any note:
````markdown
```iso-me
source: exports/iso.me-2026-05-04.json
title: Where I went
height: 500
show_visits: true
show_routes: true
```
````
`source` or `sources` is required. Every other block parameter is optional.
---
## What it renders
- **Visit markers** — duration-encoded circle markers. Longer stays are larger and more opaque. Popups show place name, address, arrival/departure time, duration, and notes when available.
- **Route polylines** — connected GPS tracks with green start marker, red end marker, and route popup showing path distance and straight-line distance.
- **GPS glitch / outlier markers** — optional scatter markers for points flagged as outliers by iso.me. Outliers are hidden by default and are always excluded from routes, route distance, and average speed.
- **Stats bar** — export format badge, visit count, point count, distance, average speed, date range, and top repeated place.
- **Interactive filters** — optional day selector and time-of-day range slider.
Supported formats:
- iso.me JSON
- iso.me CSV
- iso.me Markdown
- OwnTracks JSON
- Overland JSON / GeoJSON
- GPX
---
## Setup guide
### 1. Install the plugin
#### From Obsidian Community Plugins
If the plugin is available in Community Plugins:
1. Open **Settings → Community plugins**.
2. Disable **Restricted mode** if needed.
3. Click **Browse**.
4. Search for **iso.me Maps**.
5. Click **Install**, then **Enable**.
#### Manual install from a release
1. Download these files from the latest release:
- `manifest.json`
- `main.js`
- `styles.css`
2. In your vault, create this folder:
```text
.obsidian/plugins/iso-me-maps/
```
3. Copy the three files into that folder.
4. Restart Obsidian or run **Reload app without saving** from the command palette.
5. Open **Settings → Community plugins** and enable **iso.me Maps**.
#### Development install from this repository
```bash
npm install
npm run build
ln -s "$PWD" "/.obsidian/plugins/iso-me-maps"
```
Then reload Obsidian and enable the plugin.
### 2. Export data from iso.me
In the iso.me iOS app, export the data you want to map. Recommended options:
- Use **JSON** for the simplest one-file workflow.
- Use a combined export containing both **visits** and **points** when possible.
- If exporting CSV or Markdown visits, enable **Coordinates** in iso.me export options. Visits without latitude/longitude cannot be plotted.
- If using **One file per day**, place all generated files in a single vault folder and use a folder source, glob source, or date keyword.
### 3. Put exports in your vault
A common layout is:
```text
Your vault/
Daily Notes/
exports/
iso.me - Monday 2026-05-04 - all.json
iso.me - Tuesday 2026-05-05 - all.json
```
### 4. Configure plugin settings
Open **Settings → iso.me Maps**.
Recommended first-time settings:
| Setting | Suggested value | Why |
|---|---:|---|
| **Exports folder** | `exports` | Lets you write `source: yesterday` or `source: filename.json` instead of full paths. |
| **Export filename pattern** | `*{date}*` | Matches any file containing the resolved date. |
| **Export date format** | `YYYY-MM-DD` | Matches iso.me's default date format in filenames. |
| **Tile provider** | CartoDB Voyager | Works in desktop and mobile Obsidian. |
### 5. Add a map block
````markdown
```iso-me
source: yesterday
title: Yesterday
height: 500
interactive: true
```
````
With `exportsFolder = exports`, `source: yesterday` searches the `exports/` folder for a file matching yesterday's date.
By default, maps automatically center and zoom to the visible visits/routes/outliers in the loaded export. If you prefer a fixed initial viewport, add `auto_fit: false` plus your desired `center` and `zoom`.
---
## Complete code block parameter reference
Use parameters inside a fenced `iso-me` code block:
````markdown
```iso-me
source: exports/day.json
height: 500
zoom: 12
center: [37.7749, -122.4194]
show_visits: true
show_routes: true
show_stats: false
interactive: false
auto_fit: true
title: April trip
```
````
| Parameter | Type | Required | Default | Description |
|---|---|---:|---|---|
| `source` | path, folder, glob, or date keyword | Yes, unless `sources` is set | — | Loads one source. Can point to a supported file, a folder, a filename glob, or a date keyword such as `today`. |
| `sources` | list of paths/folders/globs/date keywords | Yes, unless `source` is set | — | Loads multiple sources and merges them into one map. Useful for separate visits + points exports or one-file-per-day batches. |
| `title` | string | No | none | Heading displayed above the map. Quotes are optional. |
| `height` | number | No | plugin **Default map height** (`400`) | Map height in pixels. |
| `zoom` | number | No | plugin **Default zoom** (`11`) | Initial/fallback zoom. If `auto_fit` is enabled and the export has one mappable coordinate, this zoom is used; multiple coordinates auto-fit the visible bounds. |
| `center` | `[latitude, longitude]` | No | plugin default center (`[0, 0]`) | Initial/fallback center when no visible layer provides bounds, or when `auto_fit: false`. |
| `auto_fit` | boolean | No | `true` | Automatically centers and zooms to the visible visits/routes/outliers. Set to `false` to use `center` and `zoom` instead. |
| `show_visits` | boolean | No | plugin **Show visit markers by default** (`true`) | Shows visit/stay markers when the export contains visits. |
| `show_routes` | boolean | No | plugin **Show routes by default** (`true`) | Shows GPS route polylines when the export contains points. Outliers are excluded. |
| `show_stats` | boolean | No | `false` | Shows the stats bar above the map. This is per-block only; there is no settings-tab default for stats. |
| `interactive` | boolean | No | `false` | Shows day and time-of-day filters above the map. Filters re-render visits, routes, and outliers. |
### Parameter syntax rules
- The code fence language must be exactly `iso-me`:
````markdown
```iso-me
source: exports/day.json
```
````
- Keys are case-insensitive, but the documented lowercase names are recommended.
- Blank lines are ignored.
- Lines beginning with `#` are comments.
- Unknown keys are ignored.
- Malformed values are ignored and the plugin falls back to defaults.
- Strings may be unquoted, single-quoted, or double-quoted:
```yaml
title: My trip
title: "My trip"
title: 'My trip'
```
- Boolean values accept all of these forms:
| True | False |
|---|---|
| `true` | `false` |
| `yes` | `no` |
| `on` | `off` |
| `1` | `0` |
- `center` must be bracketed latitude/longitude:
```yaml
center: [37.7749, -122.4194]
```
### `sources` syntax
Multi-line YAML-style list:
````markdown
```iso-me
sources:
- exports/visits.md
- exports/points.md
```
````
Inline bracket list:
````markdown
```iso-me
sources: [exports/visits.md, exports/points.md]
```
````
Inline comma list:
````markdown
```iso-me
sources: exports/visits.md, exports/points.md
```
````
If both `source` and `sources` are present, all listed sources are loaded and merged.
---
## Source resolution, date keywords, folders, and globs
A source can be any of the following:
| Source form | Example | What happens |
|---|---|---|
| File path | `source: exports/day.json` | Loads that vault-relative file. |
| Bare filename | `source: day.json` | If **Exports folder** is set, loads `exports/day.json`; otherwise loads from the vault root. |
| Folder | `source: exports/may/` | Loads every supported export file inside that folder. |
| Glob | `source: exports/iso.me*.json` | Loads every supported file in the literal directory whose filename matches the glob. |
| Date keyword | `source: yesterday` | Resolves to one or more date-based glob searches using the settings below. |
Supported file extensions are:
```text
.json, .csv, .md, .markdown, .gpx
```
### Date keywords
Date keywords are available in `source` and in each item under `sources`.
| Keyword | Meaning |
|---|---|
| `today` | Today's date. |
| `yesterday` | Yesterday's date. |
| `YYYY-MM-DD` | A specific date, for example `2026-05-04`. |
| `last N days` | Today plus the previous `N - 1` days. `N` is clamped to `1...366`. Examples: `last 7 days`, `last 30 days`, `last 365 days`. |
| `last week` | Alias for `last 7 days`. |
Examples:
````markdown
```iso-me
source: today
title: Today
```
````
````markdown
```iso-me
source: yesterday
title: Yesterday
```
````
````markdown
```iso-me
source: 2026-05-04
title: May 4, 2026
```
````
````markdown
```iso-me
source: last 7 days
title: Last week
interactive: true
```
````
### Date keyword settings
Date keywords use three settings:
| Setting | Default | Description |
|---|---|---|
| **Exports folder** | empty | Vault-relative folder to search, for example `exports`. |
| **Export filename pattern** | `*{date}*` | Glob template used to find files for a resolved date. `{date}` is replaced with the formatted date. |
| **Export date format** | `YYYY-MM-DD` | Format used when inserting dates into the filename pattern. Supported tokens: `YYYY`, `MM`, `DD`. |
With these settings:
```text
Exports folder: exports
Export filename pattern: *{date}*
Export date format: YYYY-MM-DD
```
This block:
````markdown
```iso-me
source: yesterday
```
````
resolves to a glob like:
```text
exports/*2026-05-08*
```
That matches filenames such as:
```text
exports/iso.me - Friday 2026-05-08 - all.json
exports/isome_complete_export_2026-05-08_121042.json
```
### Filename pattern examples
| Pattern | Matches |
|---|---|
| `*{date}*` | Any filename containing the date. |
| `iso.me*{date}*all*` | iso.me per-day combined files containing `all`. |
| `*{date}*visits*` | Visit-only per-day files. |
| `*{date}*points*` | Point-only per-day files. |
| `daily-{date}.json` | Exact-style filenames like `daily-2026-05-04.json`. |
If the pattern does not contain `{date}`, the plugin appends `**` to the pattern internally.
### Glob rules
- `*` matches any characters within a filename component.
- `?` matches one character within a filename component.
- Wildcards are supported in the filename only; the directory path must be literal.
- Matched files are sorted alphabetically before loading.
- Duplicate source paths are loaded only once.
- If any matched file fails to parse, the map block shows an error for that block.
---
## Plugin settings reference
Open **Settings → iso.me Maps** to configure defaults.
### Tile settings
| Setting | Stored key | Default | Description |
|---|---|---|---|
| Tile provider | `tileProvider` | `carto-voyager` | Basemap preset. |
| Tile layer URL | `tileUrl` | CartoDB Voyager URL | Leaflet tile URL template. Visible when provider is **Custom**. |
| Tile attribution | `tileAttribution` | Carto/OpenStreetMap attribution | HTML attribution shown in the map corner. Visible when provider is **Custom**. |
Available tile provider IDs:
| ID | Label | Notes |
|---|---|---|
| `carto-voyager` | CartoDB Voyager | Default. Good general-purpose map. |
| `carto-positron` | CartoDB Positron | Light basemap. |
| `carto-dark-matter` | CartoDB Dark Matter | Dark basemap. |
| `opentopomap` | OpenTopoMap | Topographic map. |
| `esri-world-imagery` | Esri World Imagery | Satellite imagery. |
| `osm` | OpenStreetMap | Mobile only; desktop Obsidian/Electron is blocked by OSM tile server referer policy. |
| `custom` | Custom | Use your own Leaflet tile URL and attribution. |
Tile setting changes apply to newly rendered maps. Already-open notes may need to be reloaded.
### Export lookup settings
| Setting | Stored key | Default | Description |
|---|---|---|---|
| Exports folder | `exportsFolder` | empty | Vault-relative folder used for bare filenames and date keywords. Trailing slashes are removed. |
| Export filename pattern | `exportFilenamePattern` | `*{date}*` | Glob template for date keyword lookup. Supports `{date}`, `*`, and `?`. |
| Export date format | `exportDateFormat` | `YYYY-MM-DD` | Date formatting tokens used by date keywords. Supports `YYYY`, `MM`, `DD`. |
### Map defaults and layer styling
| Setting | Stored key | Default | Description |
|---|---|---|---|
| Default map height | `defaultHeight` | `400` | Used when a block omits `height`. |
| Default zoom | `defaultZoom` | `11` | Used as fallback zoom and when a block omits `zoom`. |
| Default center | `defaultCenter` | `[0, 0]` | Used when no visible layer provides bounds. This setting exists in saved plugin data; it is not currently exposed in the settings UI. |
| Route color | `routeColor` | `#2563eb` | Polyline color for routes. |
| Visit marker color | `markerColor` | `#2dd4bf` | Circle marker color for visits. |
| GPS glitch color | `outlierColor` | `#f59e0b` | Marker color for outliers when shown. |
| Show visit markers by default | `showVisitsByDefault` | `true` | Default for `show_visits`. |
| Show routes by default | `showRoutesByDefault` | `true` | Default for `show_routes`. |
| Show GPS glitches by default | `showOutliersByDefault` | `false` | Controls whether points flagged as outliers / GPS glitches are shown. |
---
## Supported export formats and fields
The parser is intentionally permissive: rows or objects missing required plotting fields are skipped instead of breaking the whole export. A file-level parse error is shown only when the overall file shape is unrecognized or invalid.
### iso.me JSON
File extension: `.json`
Supported root shapes:
```json
{ "exportDate": "2026-05-04T12:00:00Z", "visits": [] }
```
```json
{ "exportDate": "2026-05-04T12:00:00Z", "points": [] }
```
```json
{ "exportDate": "2026-05-04T12:00:00Z", "visits": [], "points": [] }
```
Visit objects:
| Field | Required | Type | Description |
|---|---:|---|---|
| `latitude` | Yes | number | Visit latitude. |
| `longitude` | Yes | number | Visit longitude. |
| `arrivedAt` | Yes | string | Arrival timestamp. ISO 8601 is recommended. |
| `departedAt` | No | string or null | Departure timestamp. |
| `durationMinutes` | No | number or null | Duration used for marker sizing and popup text. |
| `locationName` | No | string or null | Place name shown in popup and top-place stats. |
| `address` | No | string or null | Address shown in popup. |
| `notes` | No | string or null | Notes shown in popup. |
Point objects:
| Field | Required | Type | Description |
|---|---:|---|---|
| `latitude` | Yes | number | Point latitude. |
| `longitude` | Yes | number | Point longitude. |
| `timestamp` | Yes | string | Point timestamp. ISO 8601 is recommended. |
| `timestampUnix` | No | number | Unix timestamp in seconds. |
| `altitude` | No | number or null | Altitude in meters. |
| `speed` | No | number or null | Speed in meters/second. Stats display average speed in km/h. |
| `course` | No | number or null | Course/bearing in degrees. Stored but not currently visualized. |
| `horizontalAccuracy` | No | number or null | Horizontal accuracy in meters. |
| `verticalAccuracy` | No | number or null | Vertical accuracy in meters. |
| `isOutlier` | No | boolean | Marks a GPS glitch/outlier. Defaults to `false`. |
### iso.me CSV
File extension: `.csv`
CSV type is detected by the header row.
#### Visits CSV
A visits CSV is detected when the header includes:
```text
arrived_at
```
Required columns for plotted rows:
| Column | Required | Description |
|---|---:|---|
| `arrived_at` | Yes | Arrival timestamp. |
| `latitude` | Yes | Visit latitude. Enable coordinates in iso.me export options. |
| `longitude` | Yes | Visit longitude. Enable coordinates in iso.me export options. |
Optional columns:
| Column | Description |
|---|---|
| `departed_at` | Departure timestamp. |
| `duration_minutes` | Visit duration. |
| `location_name` | Place name. |
| `address` | Address. |
| `notes` | Notes. |
Rows without `arrived_at`, `latitude`, or `longitude` are skipped.
#### Points CSV
A points CSV is detected when the header includes all of:
```text
timestamp, latitude, longitude
```
Required columns for plotted rows:
| Column | Required | Description |
|---|---:|---|
| `timestamp` | Yes | Point timestamp. |
| `latitude` | Yes | Point latitude. |
| `longitude` | Yes | Point longitude. |
Optional columns:
| Column | Description |
|---|---|
| `timestamp_unix` | Unix timestamp in seconds. |
| `altitude` | Altitude in meters. |
| `speed` | Speed in meters/second. |
| `horizontal_accuracy` | Horizontal accuracy in meters. |
| `is_outlier` | Outlier flag. Accepted true values: `true`, `yes`, `1`. |
### iso.me Markdown
File extensions: `.md`, `.markdown`
Markdown parsing assumes iso.me's default English date/time export format, for example:
```text
Friday, March 14, 2025
3:24 PM
3:24:05 PM
15:24
15:24:05
```
Supported H1 sections:
| H1 | Parsed as |
|---|---|
| `# iso.me Export` | Visits. |
| `# Visits` | Visits. |
| Any H1 containing `iso.me` | Visits, unless it is a location-points or complete-export heading. |
| `# iso.me Location Points Export` | Location points. |
#### Visits Markdown — bullet format
Expected structure:
```markdown
# iso.me Export
## Friday, March 14, 2025
### Coffee Shop
- **Arrived:** 8:12 AM
- **Departed:** 8:45 AM
- **Duration:** 33m
- **Address:** 123 Market St
- **Coordinates:** 37.7749, -122.4194
> Optional notes
```
Supported bullet fields:
| Field | Required | Description |
|---|---:|---|
| `Arrived` | Yes | Arrival time. |
| `Coordinates` | Yes | `latitude, longitude`. |
| `Departed` | No | Departure time. |
| `Duration` | No | Text containing hours/minutes, for example `1h 20m` or `33m`. |
| `Address` | No | Address. |
| blockquote notes | No | Lines beginning with `> `. |
The `###` heading is used as `locationName` unless the heading itself is just a time.
#### Visits Markdown — table format
The parser also accepts visit tables with at least these columns:
```text
Arrived, Lat, Lon
```
Optional columns:
```text
Departed, Duration, Location, Address, Notes
```
#### Points Markdown — table format
Expected H1:
```markdown
# iso.me Location Points Export
```
The point table must include:
```text
Time, Lat, Lon
```
Optional columns:
```text
Altitude, Speed, Accuracy, Outlier
```
`Outlier` is true when the cell is `yes` or `true`.
### OwnTracks JSON
File extension: `.json`
Detected when the JSON root is an array whose first object looks like an OwnTracks location:
```json
[
{
"_type": "location",
"lat": 37.7749,
"lon": -122.4194,
"tst": 1777891200,
"acc": 10,
"alt": 12,
"vel": 18,
"cog": 270,
"vac": 5
}
]
```
Supported fields:
| Field | Required | Description |
|---|---:|---|
| `_type` | Yes | Must be `location`. |
| `lat` | Yes | Latitude. |
| `lon` | Yes | Longitude. |
| `tst` | Yes | Unix timestamp in seconds. |
| `acc` | No | Horizontal accuracy in meters. |
| `alt` | No | Altitude in meters. |
| `vel` | No | Speed in km/h; converted internally to meters/second. |
| `cog` | No | Course over ground in degrees. |
| `vac` | No | Vertical accuracy in meters. |
| `tid` | No | Tracker ID. Accepted but not displayed. |
OwnTracks files contain points only, so visit markers are not rendered.
### Overland JSON / GeoJSON
File extension: `.json`
Detected when the JSON root has a `locations` array of GeoJSON point features:
```json
{
"locations": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-122.4194, 37.7749]
},
"properties": {
"timestamp": "2026-05-04T12:00:00Z",
"altitude": 12,
"speed": 4.2,
"horizontalAccuracy": 10,
"deviceId": "iphone"
}
}
]
}
```
Supported fields:
| Field | Required | Description |
|---|---:|---|
| `locations[]` | Yes | Array of GeoJSON features. |
| `type` | Yes | Feature type must be `Feature`. |
| `geometry.type` | Yes | Geometry type must be `Point`. |
| `geometry.coordinates` | Yes | `[longitude, latitude]` order. |
| `properties.timestamp` | Yes | Timestamp string. |
| `properties.altitude` | No | Altitude in meters. |
| `properties.speed` | No | Speed in meters/second. |
| `properties.horizontalAccuracy` | No | Horizontal accuracy in meters. |
| `properties.deviceId` | No | Accepted but not displayed. |
Overland files contain points only, so visit markers are not rendered.
### GPX
File extension: `.gpx`
The parser uses the browser's built-in `DOMParser`, available in desktop and mobile Obsidian.
Supported GPX content:
| Element | Parsed as | Required data |
|---|---|---|
| `` | Visit | `lat`, `lon`, and child `