This template includes IP geolocation powered by IPinfo, enabling you to detect user location for features like dynamic pricing, localized content, and country-specific experiences.
The geolocation integration provides:
Add your IPinfo API token to .env:
IPINFO_TOKEN="your_ipinfo_token"
The template includes two endpoints:
/api/ip - Returns IP info for the current request
Returns: { ip, hostname, city, region, country, loc, org, postal, timezone }
/api/ip/[ipAddress] - Returns IP info for a specific IP address
Example: /api/ip/8.8.8.8
Both endpoints use getIpInfo() from server/services/ip-server-service.ts.
<script setup>
const { data: ipInfo } = await useFetch('/api/ip')
</script>
<template>
<div>
<p>Country: {{ ipInfo?.country }}</p>
<p>City: {{ ipInfo?.city }}</p>
<p>Timezone: {{ ipInfo?.timezone }}</p>
</div>
</template>
Detect user's country and show appropriate currency:
<script setup>
const { data: ipInfo } = await useFetch('/api/ip')
const currency = computed(() => {
const country = ipInfo.value?.country
if (country === 'GB') return 'GBP'
if (['DE', 'FR', 'ES', 'IT'].includes(country)) return 'EUR'
return 'USD'
})
const price = computed(() => {
const prices = { USD: 29, EUR: 25, GBP: 22 }
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: currency.value,
}).format(prices[currency.value])
})
</script>
<template>
<div>{{ price }}/month</div>
</template>
Pass the user's country to your checkout endpoint:
export default defineEventHandler(async event => {
const { plan, interval } = await readBody(event)
// Get user's location
const ipInfo = await getIpInfo()
// Map country to Stripe price ID
// You'll need to create price IDs for each currency in Stripe
const priceId = getPriceIdForCountry(plan, interval, ipInfo.country)
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [{ price: priceId, quantity: 1 }],
// ...
})
return { url: session.url }
})
Show different content or messages based on user's country:
<script setup>
const { data: ipInfo } = await useFetch('/api/ip')
const welcomeMessage = computed(() => {
const messages = {
US: 'Welcome! 🇺🇸',
DE: 'Willkommen! 🇩🇪',
FR: 'Bienvenue! 🇫🇷',
}
return messages[ipInfo.value?.country] || 'Welcome!'
})
</script>
Restrict access based on location in server middleware:
export default defineEventHandler(async event => {
const ipInfo = await getIpInfo()
const blockedCountries = ['XX', 'YY']
if (blockedCountries.includes(ipInfo.country)) {
throw createError({
statusCode: 403,
message: 'Service not available in your region',
})
}
})
Allow users to manually select their currency/location:
<script setup>
const { data: ipInfo } = await useFetch('/api/ip')
const userCurrency = useCookie('user-currency')
const currency = computed({
get: () => userCurrency.value || getCurrencyFromCountry(ipInfo.value?.country),
set: (value) => { userCurrency.value = value }
})
</script>
<template>
<Select v-model="currency">
<SelectItem value="USD">USD</SelectItem>
<SelectItem value="EUR">EUR</SelectItem>
<SelectItem value="GBP">GBP</SelectItem>
</Select>
</template>
GDPR compliance: IP-based geolocation is generally acceptable under GDPR as IPs are used for technical purposes. Include geolocation usage in your privacy policy.
Caching: The free tier provides unlimited API requests, but consider caching IP lookups to improve performance and reduce latency.
Error handling: Always provide fallback values (e.g., default to 'US' or 'USD') if geolocation fails.