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/meonly - 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.
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.
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.
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');<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.
<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.