How to Detect Visitor Country and Currency in JavaScript (No Backend Required)

You want to show prices in the right currency, tailor your CTA to the visitor’s region, or auto-select a country in a checkout form. All of that starts with one question: where is this person? And more specifically: what currency do they use?
The answer is a single API call that runs entirely in the browser — no backend, no secret key stored on a server, and no prompting the user to allow anything. This tutorial walks through exactly how to do it, with copy-paste examples in both vanilla JavaScript and React.
Why not the browser Geolocation API?
The browser Geolocation API (navigator.geolocation) returns latitude and longitude — it does not give you a country code, and it certainly does not give you a currency. You would need to reverse-geocode those coordinates through a second API call, and even then you still would not have currency data. On top of that, it fires a permission prompt in the browser, which many users dismiss. It is the right tool for “show me a map”, not for “show me prices in the right currency”.
What you’ll build
By the end of this tutorial you will have a working snippet that:
- Detects the visitor’s country code (e.g.
GB,DE,AU) - Returns the currencies used in that country (e.g.
["GBP"],["EUR"],["AUD"]) - Works from a
<script>tag or a React component — no backend involved - Requires zero configuration beyond a free Project ID
Prerequisites
- A free VisitorAPI account — takes about two minutes to create
- A Project ID (created in the dashboard after sign-up)
- Your domain added to the project’s allowed-domain list
The free tier covers 1,000 requests per month, which is enough for development and small production sites.
Step 1: Get your Project ID
Sign up at app.visitorapi.com and create a new project. Give it a name, then add your domain to the Allowed Domains list — this is the authorisation mechanism VisitorAPI uses instead of an API key. Requests from unlisted domains return a 403, and requests from listed domains are accepted without any secret token.
Copy the Project ID shown on the project page. It will look something like abc123xyz. That string is the only value you need to embed in your frontend code — it is not a secret.
Step 2: Detect country and currency with one API call
VisitorAPI exposes a public endpoint at https://api.visitorapi.com/api/?pid=<your_project_id>. You can call it with a plain fetch(), or via the visitorapi npm package which adds caching and a cleaner API.
Vanilla JS — using fetch directly:
async function getVisitorLocation() {
const response = await fetch(
"https://api.visitorapi.com/api/?pid=YOUR_PROJECT_ID"
);
const data = await response.json();
console.log(data.countryCode); // e.g. "DE"
console.log(data.currencies); // e.g. ["EUR"]
console.log(data.countryName); // e.g. "Germany"
return data;
}
getVisitorLocation();
Using the npm package (recommended for bundled projects):
npm install visitorapi
import VisitorAPI from "visitorapi";
VisitorAPI("YOUR_PROJECT_ID").then(data => {
console.log(data.countryCode); // "DE"
console.log(data.currencies); // ["EUR"]
}).catch(error => {
console.error("VisitorAPI error:", error);
});
The currencies field is an array because some countries have more than one official currency. Always read data.currencies[0] if you need a single value, and handle the multi-currency case where relevant.
Step 3: Use the data in your UI
Knowing the visitor’s country and currency is only useful if you wire it into your UI. Here are three common patterns.
Auto-select a currency in a <select> dropdown:
async function setCurrencySelector() {
try {
const response = await fetch(
"https://api.visitorapi.com/api/?pid=YOUR_PROJECT_ID"
);
const data = await response.json();
const primaryCurrency = data.currencies[0]; // e.g. "GBP"
const selector = document.getElementById("currency-selector");
if (selector) {
// Set the matching option if it exists, fall back to USD
const option = selector.querySelector(`option[value="${primaryCurrency}"]`);
if (option) {
selector.value = primaryCurrency;
} else {
selector.value = "USD";
}
}
} catch (err) {
// Fail silently — leave the default currency in place
console.warn("Could not detect visitor currency:", err);
}
}
document.addEventListener("DOMContentLoaded", setCurrencySelector);
Display localised prices using the Intl API:
async function showLocalPrice(amountUSD) {
const response = await fetch(
"https://api.visitorapi.com/api/?pid=YOUR_PROJECT_ID"
);
const data = await response.json();
const currency = data.currencies[0] || "USD";
const locale = navigator.language || "en-US";
return new Intl.NumberFormat(locale, {
style: "currency",
currency: currency,
}).format(amountUSD);
}
A few things to keep in mind: always wrap API calls in try/catch so a network failure does not break your UI. Use the detected currency as a hint, not a guarantee — give users a way to override it. And cache the result in sessionStorage to avoid repeated calls on the same visit.
Full working HTML example
Drop this into any HTML file and replace YOUR_PROJECT_ID to see it working immediately:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Visitor Location Demo</title>
</head>
<body>
<p>Detected country: <strong id="country">detecting…</strong></p>
<p>Primary currency: <strong id="currency">detecting…</strong></p>
<script>
(async () => {
try {
const res = await fetch(
"https://api.visitorapi.com/api/?pid=YOUR_PROJECT_ID"
);
const data = await res.json();
document.getElementById("country").textContent =
data.countryName + " (" + data.countryCode + ")";
document.getElementById("currency").textContent =
data.currencies[0] || "unknown";
} catch (e) {
document.getElementById("country").textContent = "unavailable";
document.getElementById("currency").textContent = "unavailable";
}
})();
</script>
</body>
</html>
Save it, open it in a browser with your Project ID in place, and you will see your country and currency appear within a second or two.
React version
Install the package once:
npm install visitorapi
Then use it in a component with useEffect:
import { useState, useEffect } from "react";
import VisitorAPI from "visitorapi";
export function CurrencyDisplay() {
const [country, setCountry] = useState(null);
const [currency, setCurrency] = useState(null);
useEffect(() => {
VisitorAPI("YOUR_PROJECT_ID")
.then(data => {
setCountry(data.countryCode);
setCurrency(data.currencies[0] || "USD");
})
.catch(err => {
console.warn("VisitorAPI error:", err);
});
}, []);
if (!country) return <span>Detecting location…</span>;
return (
<span>
{country} — {currency}
</span>
);
}
Call VisitorAPI inside useEffect with an empty dependency array so it runs once on mount. The promise resolves in a few hundred milliseconds on the first call; subsequent calls within the same session are served from the SDK’s built-in cache.
Why this is safe to call from the frontend
The usual concern about client-side API calls is that someone will scrape your key and abuse it. VisitorAPI sidesteps this by not using API keys at all. Authorisation is by domain allowlist: you list the domains permitted to call your project in the dashboard, and the API validates the request origin against that list. A request from an unlisted domain returns a 403 regardless of what Project ID is used.
Your Project ID is therefore safe to embed directly in JavaScript — it only works from domains you explicitly authorise, so there is nothing to steal. This is the same model used by Firebase’s public config keys, which are also safe to ship in frontend code.
What else you can detect
The same API call that returns countryCode and currencies also returns:
countryName— full country name (e.g. “United Kingdom”)languages— array of official languages (e.g.["en"],["fr", "en"])region— state or province (e.g. “England”, “California”)city— city namebrowserandbrowserVersion— browser identificationosandosVersion— operating systemdeviceBrand,deviceModel,deviceFamily— mobile device info
This covers the majority of personalisation and locale-detection use cases from a single HTTP call. See the full API reference for the complete field list.
Start detecting visitors now
Create a free VisitorAPI project — it takes two minutes, the free tier is 1,000 requests per month with no credit card required, and the integration is a single function call.
If you are already using VisitorAPI and want to push this data into Google Tag Manager instead of reading it in JavaScript, see Add Visitor Currency and Language to Google Tag Manager.