JavaScript / TypeScript

Browser & frameworks

@ipgeotrace/browser resolves the current visitor's location from client-side code with a publishable key. React, Vue and Svelte bindings wrap it so you resolve once and read the result reactively across your app.

The browser only ever asks one question - where is the person looking at this page? - which is exactly what me()answers, because the API sees the browser's real connection IP. There is no IP to supply and no batch; just the visitor.

Publishable keys#

The browser cannot hold a secret, so it uses a publishable key (sent as X-Api-Key), like a Google Maps browser key. It is safe to ship in your bundle because it is restricted:

  • domain-locked to the origins you allow;
  • scoped to resolve/me only - no arbitrary lookups, no batch;
  • rate-limited independently of your secret key.

Keep the two keys apart

The secret key stays on your server in @ipgeotrace/client and never reaches the browser. Only the publishable key belongs in client-side code.

Vanilla browser client#

createBrowserClient().me() returns the same Result shape as the core - check ok before reading value. This is the entire browser SDK; the framework packages below are optional reactive wrappers over it.

ts
import { createBrowserClient } from '@ipgeotrace/browser';

const client = createBrowserClient({ publishableKey: 'pk_geoip_your_key' });

const result = await client.me();
if (result.ok) {
  document.body.dataset.currency = result.value.country?.currency ?? 'USD';
} else {
  console.warn(result.error.code); // e.g. 'rate_limited'
}

React#

Wrap your tree in <IpGeoTraceProvider>; it calls me() once and shares the result. useVisitorGeo() gives you { data, error, loading, refresh }. The hook is marked "use client", so it serves Next.js client components too.

tsx
import { IpGeoTraceProvider, useVisitorGeo } from '@ipgeotrace/react';

export function App() {
  return (
    <IpGeoTraceProvider publishableKey="pk_geoip_your_key">
      <Greeting />
    </IpGeoTraceProvider>
  );
}

function Greeting() {
  const { data, loading } = useVisitorGeo();
  if (loading) return <p>Locating you</p>;
  return <p>Prices shown in {data?.country?.currency ?? 'USD'}</p>;
}

Vue#

Install the plugin once; it resolves me() and provides a reactive useVisitorGeo() composable to every component.

ts
import { createApp } from 'vue';
import { ipgeotrace } from '@ipgeotrace/vue';
import App from './App.vue';

createApp(App).use(ipgeotrace, { publishableKey: 'pk_geoip_your_key' }).mount('#app');
vue
<script setup lang="ts">
import { useVisitorGeo } from '@ipgeotrace/vue';

const { data, loading } = useVisitorGeo();
</script>

<template>
  <p v-if="loading">Locating you</p>
  <p v-else>Prices shown in {{ data?.country?.currency ?? 'USD' }}</p>
</template>

Svelte#

createVisitorGeo() returns a readable store you subscribe to with $. Share one call across components with the setVisitorGeo / useVisitorGeo context helpers.

svelte
<script lang="ts">
  import { createVisitorGeo } from '@ipgeotrace/svelte';

  const visitor = createVisitorGeo({ publishableKey: 'pk_geoip_your_key' });
</script>

{#if $visitor.loading}
  <p>Locating you</p>
{:else}
  <p>Prices shown in {$visitor.data?.country?.currency ?? 'USD'}</p>
{/if}

Each binding exposes the same reactive shape - data, error, loading and a refresh() to resolve again on demand. They add DX, not capability: you can always call @ipgeotrace/browser directly from a useEffect or onMounted.

Need server-side lookups?

To geolocate the caller in an API route or resolve arbitrary IPs, see Server (Node & edge). Grab a publishable key from app.ipgeotrace.com.