LogoRapidstack.pro

Geolocation

Detect visitor country, city and timezone with IPinfo, then use it for country-based pricing and location-aware Stripe checkout sessions.

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.

Overview

The geolocation integration provides:

  • IP-based location detection - Country, city, region, timezone.
  • Two API endpoints - Get current user's location or query specific IPs.
  • Server-side processing - Secure API key management.
  • Privacy-focused - No personal data storage required.

Configuration

Add your IPinfo API token to .env:

.env
IPINFO_TOKEN="your_ipinfo_token"
Sign up at IPinfo to get your token. The free tier (IPinfo Lite) includes unlimited API requests with 7 essential IP attributes (country, continent, ASN). Paid plans start at $49/month for city-level accuracy and privacy detection.

API endpoints

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.

Usage examples

Get current user's location

<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>

Dynamic pricing by country

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>

Stripe checkout with location-based pricing

Pass the user's country to your checkout endpoint:

server/api/stripe/create-checkout-session.post.ts
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 }
})

Additional use cases

Localized content

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>

Regional restrictions

Restrict access based on location in server middleware:

server/middleware/geo-check.ts
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',
    })
  }
})

User preference override

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>

Privacy and performance

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.

Reference

Always provide fallback values (default country/currency) in case geolocation fails due to network issues or missing API token configuration.