Mobile: Can Obsidian API provide current geo location (GPS) on Android/iOS?

Use case or problem

Easily get at the current geo position (GPS) on a mobile device that runs Obsidian.
Mainly to update a “current location” note, for use with the Obsidian Leaflet maps.

Proposed solution / current workaround

On my laptop, I use Templater to update a “Current Location” note by calling a Python script that evaluates my current geo location (from the laptop’s GPS or IP address).

I’d very much like to see that on the mobile version, so I could have a “live view” of my Obsidian Leaflet maps. It’s of course not that easy on a smartphone: Users have to consent reading the GPS location, and I wonder if it’s available in Typescript/Javascript, instead of running external code.

So the best bet would be that the Obsidian API could support that functionality and provide some means for a plugin (or JS code) to read out the location data, i.e. at least latitude and longitude (WGS 84), maybe even elevation (meters).

Thus, plugins like Obsidian Leaflet maps could use it directly, and notes using Templater and/or Dataview scripting could also use it.

Is that possible? Or planned?

I feel this could be a real cool feature.

Related feature requests (optional)

8 Likes

There are some NPM packages dealing with geolocation. E.g., geolocation - npm

I don’t know what would happen if a plugin tried to use them on mobile, though. I imagine it would just fail silently…

Looks like Capacitor has an official geolocation plugin. Would probably be better to use that for mobile.

On desktop, the Google API key has to be set and have Geolocation permissions in Electron to use Chromium’s geolocation API. See here.

1 Like

<rant>

So on Android you have to get a Google API key for a function that the phone’s hardware provides.

Ridiculous scheme, eh? Getting the data from almost everyone for free and making them pay (for many requests) to be able to access their own data!

</rant>

2 Likes

I’d love to see this feature. One thing I like about Evernote is the metadata in every note: I know when and where each note was composed. If I could have this info in a template in Obsidian, that would be great.

1 Like

It would be great to get accurate GPS location, but this is what I’m doing on mobile for general location using Templater. It requires an internet connection, and will insert a placeholder (or blank) if none is available.

Works great on desktop or mobile. Templater script:

<%*
return Promise.race([
    new Promise((resolve) => {
        fetch('http://ip-api.com/json/')
            .then(response => response.json())
            .then(data => resolve([data.city, data.regionName, data.country].filter(x => !!x).join(', ')))
    }),
    new Promise((resolve) =>
        // If we haven't fetched the location within 300ms,
        // time-out and resolve with the placeholder text instead
        setTimeout(() => resolve('Location'), 300)
    )
])
%>
4 Likes

How would you use this with Obsidian Leaflet? Glancing at the docs for that plugin, I don’t see an easy way for it to import locations from multiple notes.

Hello!

I know this is some months old, but I was wondering - where do you put this exactly?

I’m new here to Obsidian and I’ve tried adding it to my notes, but it just loads the location and removes everything else. I did see in the docs for templater about about user scripts, but I cannot make it load! I’d like to have it in my ymal with everything else. (date created, modified, tags, etc.,)

Any help would be appreciated as i’d love to use it because it does load my location :slight_smile:

If you’re including it inside another template, you need to use the tR variable. Here’s a fully working example:

---
some_field: blah blah
location: <%* tR += await Promise.race([
    new Promise((resolve) => {
        fetch('http://ip-api.com/json/')
            .then(response => response.json())
            .then(data => resolve([data.city, data.regionName, data.country].filter(x => !!x).join(', ')))
    }),
    new Promise((resolve) =>
        // If we haven't fetched the location within 300ms,
        // time-out and resolve with the placeholder text instead
        setTimeout(() => resolve('Location'), 300)
    )
])
%>
another_field: blah blah
---

Other template stuff.

1 Like

Hmm, okay bear with me please as I’m new/lost a bit.

I added that to my template for my daily notes and I got a parsing error. Where should I add that snippet?

Also, is it possible to create a user function like the docs say?

https://silentvoid13.github.io/Templater/user-functions/script-user-functions.html

Brilliantly useful. Thanks for sharing. :clap:

1 Like

Yes for sure, that’s the way I do it in my vault. Use the original code with return, not the one with tR

Thanks so much for your help, but I’m still stuck :frowning:

I took your original code above (with return) and created a .js file and placed the .js file (named location.js) in a scripts folder and made sure templater saw it in setting. Then and when I call it in my daily notes template

 <% tp.user.location() %>

it continues to say there is a parsing issue and it doesn’t run.

What could I be doing wrong?

Ah, I got it!

I wrapped it in a function. I suppose for the sake of learning in public, I’ll post what I did so if anyone else that’s new comes along and wants to add locations to their notes, they can.

Follow the instructions to create a script folder in the vault and then add your .js file to that folder, and then call it within your notes.

Here’s the code @AlanG originally wrote above that’s in my location.js file I wrapped in a function:

function location() {
    return Promise.race([
        new Promise((resolve) => {
            fetch('http://ip-api.com/json/')
                .then(response => response.json())
                .then(data => resolve([data.city, data.regionName, data.country].filter(x => !!x).join(', ')))
        }),
        new Promise((resolve) =>
            // If we haven't fetched the location within 300ms,
            // time-out and resolve with the placeholder text instead
            setTimeout(() => resolve('Location'), 300)
        )
    ])
}

module.exports = location;

and then in my notes template, I call it by adding:

<% tp.user.location() %>

If there is a better way, please let me know! However, this seems to be working for me :slight_smile:

Thanks so much for your help!

1 Like