ragnarok22/whereami.nvim

github github
utility
stars 22
issues 0
subscribers 1
forks 1
CREATED

UPDATED


Whereami.nvim

CI Neovim 0.9+ License GitHub stars Last commit Ask DeepWiki

Check the approximate location of your current public IP without leaving Neovim. Whereami.nvim is useful for confirming that a VPN is connected to the expected country, city, and network.

[!NOTE] IP geolocation is approximate. It identifies the location associated with your public or VPN exit IP, not your exact physical location.

Features

  • Country code and flag notifications
  • City, public IP, and network organization details
  • Automatic fallback between location providers
  • In-memory response caching and manual refreshes
  • Optional display masking for private location fields
  • Support for Neovim's built-in notifications and nvim-notify

Table of Contents

Installation

Requirements

  • Neovim 0.9 or newer
  • plenary.nvim
  • Network access to the configured location providers
  • An emoji-capable terminal and font for country flags (optional)

lazy.nvim

{
  "ragnarok22/whereami.nvim",
  cmd = "Whereami",
  dependencies = { "nvim-lua/plenary.nvim" },
}

Whereami.nvim works with its defaults, so calling setup() is optional. To configure it with lazy.nvim, add an opts table:

{
  "ragnarok22/whereami.nvim",
  cmd = "Whereami",
  dependencies = { "nvim-lua/plenary.nvim" },
  opts = {
    default_command = "all",
  },
}

pckr.nvim

local cmd = require("pckr.loader.cmd")

require("pckr").add({
  {
    "ragnarok22/whereami.nvim",
    requires = { "nvim-lua/plenary.nvim" },
    cond = cmd("Whereami"),
  },
})

packer.nvim (legacy)

packer.nvim is deprecated, but existing configurations can install Whereami.nvim with:

use({
  "ragnarok22/whereami.nvim",
  cmd = "Whereami",
  requires = { "nvim-lua/plenary.nvim" },
})

Configuration

Call setup() to override any defaults. Each call resets unspecified options to their defaults and clears cached location data.

require("whereami").setup({
  default_command = "all",
  cache_ttl = 300000,
  privacy = {
    mask_ip = true,
    hide_city = false,
    hide_isp = false,
  },
})

Options

Option Default Description
provider_url nil Use one provider URL instead of the default provider list.
providers nil A provider string, provider table, or ordered list of providers.
timeout 5000 Request timeout per provider, in milliseconds.
default_command "country" Notification shown by :Whereami and whereami.whereami(). Use country, city, ip, isp, or all.
cache_ttl 300000 Cache duration in milliseconds. Set to 0 to disable caching.
notification.title "Where am I?" Title passed to vim.notify.
notification.icons.country_fallback "🌎" Icon used when a country code is unavailable or invalid.
notification.icons.default "❔" Icon used for non-country notifications.
privacy.mask_ip false Mask part of the IP address in notifications.
privacy.hide_city false Display hidden instead of the city in notifications.
privacy.hide_isp false Display hidden instead of the network organization in notifications.
hooks.before_request nil Function called before a fresh provider request cycle.
hooks.after_request nil Function called after fresh location data is successfully accepted.

Notifications

Whereami.nvim uses vim.notify, so it works with Neovim's default notifications. To use nvim-notify with lazy.nvim:

{
  "ragnarok22/whereami.nvim",
  cmd = "Whereami",
  dependencies = {
    "nvim-lua/plenary.nvim",
    {
      "rcarriga/nvim-notify",
      config = function()
        require("notify").setup({})
        vim.notify = require("notify")
      end,
    },
  },
}

Providers

By default, Whereami.nvim tries ipinfo.io and falls back to ipapi.co if the first provider fails or returns no usable location fields.

Use provider_url for one endpoint that returns at least one supported field: ip, city, country, or org.

require("whereami").setup({
  provider_url = "https://ipinfo.io/json",
})

For custom response formats, define an ordered provider list and normalize each response:

require("whereami").setup({
  providers = {
    { url = "https://ipinfo.io/json" },
    {
      url = "https://ipapi.co/json/",
      normalize = function(data)
        return {
          ip = data.ip,
          city = data.city,
          country = data.country_code,
          org = data.org or data.asn,
        }
      end,
    },
  },
})

Each provider must define either:

  • url: The JSON endpoint requested with plenary.curl.
  • fetch(config): A custom request function used instead of url.

Providers can also define normalize(data) to map their response to ip, city, country, and org. provider_url takes precedence over providers. Accepted data must contain at least one supported location field; without a normalizer, additional provider-specific fields are preserved.

Request Hooks

Hooks run only for fresh requests, not cache hits:

require("whereami").setup({
  hooks = {
    before_request = function(config)
      vim.notify("Checking location with a " .. config.timeout .. " ms timeout")
    end,
    after_request = function(data, config)
      vim.notify("Location response received for " .. (data.ip or "unknown IP"))
    end,
  },
})

before_request runs once before the provider fallback cycle. after_request runs only after a provider returns accepted location data.

Usage

Run :Whereami to show the configured default notification. The default is the country associated with your current public IP.

For a complete VPN check:

:Whereami all

To bypass cached data after connecting to a different VPN server:

:Whereami refresh

Commands

Command Behavior
:Whereami Run the configured default_command.
:Whereami country Show the country code and flag.
:Whereami city Show the approximate city.
:Whereami ip Show the public IP address.
:Whereami isp Show the network organization or ISP.
:Whereami all Show country, city, IP address, and network organization.
:Whereami json Print unmasked location data as JSON.
:Whereami refresh Clear the cache, fetch fresh data, and show the country.

Lua API

local whereami = require("whereami")

whereami.whereami()   -- show the configured default notification
whereami.country()    -- show the country
whereami.city()       -- show the city
whereami.ip()         -- show the public IP
whereami.isp()        -- show the network organization
whereami.all()        -- show all location fields
whereami.clear_cache()

local data, err = whereami.get()
local fresh_data, refresh_err = whereami.refresh()

get() returns location data or nil, error. The default providers return the fields ip, city, country, and org; custom providers may preserve additional fields. refresh() clears the cache and returns freshly fetched data without displaying a success notification. Use :Whereami refresh when you want both a fresh request and visible output.

Keymaps

local whereami = require("whereami")

vim.keymap.set("n", "<leader>vc", whereami.country, {
  desc = "Check VPN country",
})

vim.keymap.set("n", "<leader>va", whereami.all, {
  desc = "Check VPN location details",
})

vim.keymap.set("n", "<leader>vr", "<cmd>Whereami refresh<cr>", {
  desc = "Refresh VPN location",
})

Privacy and Network Behavior

Whereami.nvim contacts a third-party IP geolocation provider when it needs fresh data.

  • The provider receives your current public IP address and normal HTTP request metadata.
  • Built-in requests do not send Neovim buffers, files, or editor configuration.
  • IP geolocation is approximate and may report the provider's nearest known network location.
  • Privacy options change notification output only. whereami.get() and :Whereami json return unmasked location data.
  • Successful responses are cached in memory for five minutes by default and are never persisted between Neovim sessions.
  • Provider requests are synchronous and use the configured timeout for each attempted provider.

Review the privacy policy and terms of every provider you configure. Use cache_ttl = 0 to disable caching, clear_cache() to remove cached data, or :Whereami refresh to force a new request.

Health Checks

Run the built-in health check when installation or requests are not working:

:checkhealth whereami

It verifies that plenary.curl is available, checks JSON decoding, reports information about vim.notify, and tests connectivity to https://ipinfo.io/json. The reachability check always uses ipinfo.io, even when a custom provider is configured.

If your plugin manager loads Whereami.nvim only for the :Whereami command, load the plugin first by running :Whereami or your manager's explicit load command.

Development

Setup

Clone plenary.nvim into the recommended repository-local dependency directory:

git clone --depth 1 https://github.com/nvim-lua/plenary.nvim .deps/plenary.nvim

Alternatively, set PLENARY_NVIM_PATH to an existing checkout. The test bootstrap also recognizes deps/plenary.nvim, tests/deps/plenary.nvim, and standard lazy.nvim or native package locations.

Checks

Run formatting and lint checks from the repository root:

stylua --check .
selene .

Run the Plenary test suite with the test bootstrap as Neovim's startup file:

nvim --headless -u tests/minimal_init.lua -c "PlenaryBustedDirectory lua/tests {minimal_init = 'tests/minimal_init.lua'}" +qa

Check README links with:

lychee --verbose --no-progress README.md

GitHub Actions runs these checks for pushes to main and for pull requests.

Contributing and Security

License

GNU GPLv3