FlagsCountries APIHTMLCSSTutorial
Country Flags API: Display Country Flags in HTML and CSS
ApogeoAPI5 min read
Three ways to display country flags
- CSS emoji flags — browser-rendered, no images, works everywhere modern
- SVG flag CDN — crisp at any size, accessible via country code
- ApogeoAPI flagUrl field — get the CDN URL directly from the countries API
Method 1: CSS emoji flags
Convert a 2-letter ISO country code to a flag emoji using Unicode regional indicator symbols:
function countryCodeToEmoji(countryCode) {
// Each letter maps to a Regional Indicator Symbol (U+1F1E6 = 🇦)
return countryCode
.toUpperCase()
.split('')
.map(char => String.fromCodePoint(char.charCodeAt(0) + 127397))
.join('');
}
countryCodeToEmoji('US'); // 🇺🇸
countryCodeToEmoji('DE'); // 🇩🇪
countryCodeToEmoji('BR'); // 🇧🇷
countryCodeToEmoji('JP'); // 🇯🇵
Render in HTML with accessible aria-label:
// React component
function Flag({ countryCode, countryName }) {
const emoji = countryCode
.toUpperCase()
.split('')
.map(c => String.fromCodePoint(c.charCodeAt(0) + 127397))
.join('');
return (
<span
role="img"
aria-label={`Flag of ${countryName}`}
className="text-2xl"
>
{emoji}
</span>
);
}
// Usage
<Flag countryCode="US" countryName="United States" /> // 🇺🇸
Note: Windows renders emoji flags as 2-letter text (US, DE) rather than flag images. If Windows support matters, use SVG instead.
Method 2: SVG flag CDN (flagcdn.com)
flagcdn.com serves SVG flags for every ISO 3166-1 alpha-2 country code — free, no API key:
<!-- Format: https://flagcdn.com/{lowercase-iso2}.svg -->
<img
src="https://flagcdn.com/us.svg"
alt="United States flag"
width="32"
height="24"
loading="lazy"
/>
function getFlagUrl(countryCode, width = 32) {
// flagcdn.com supports width-based PNG: /w{width}/{code}.png
// or SVG: /{code}.svg
const code = countryCode.toLowerCase();
return `https://flagcdn.com/${code}.svg`;
// For PNG with specific width: `https://flagcdn.com/w${width}/${code}.png`
}
getFlagUrl('US'); // "https://flagcdn.com/us.svg"
getFlagUrl('DE'); // "https://flagcdn.com/de.svg"
Method 3: ApogeoAPI countries endpoint
ApogeoAPI returns a flagUrl field directly from the countries endpoint:
GET https://api.apogeoapi.com/v1/countries/US?apikey=YOUR_KEY
# Response includes:
{
"iso2": "US",
"commonName": "United States",
"flagUrl": "https://flagcdn.com/us.svg",
"currencyCode": "USD",
"dialCode": "+1",
...
}
async function getCountryWithFlag(countryCode) {
const res = await fetch(
`https://api.apogeoapi.com/v1/countries/${countryCode}?apikey=${process.env.APOGEO_KEY}`
);
const country = await res.json();
return {
name: country.commonName,
flag: country.flagUrl,
currency: country.currencyCode,
dialCode: country.dialCode,
};
}
const us = await getCountryWithFlag('US');
// { name: "United States", flag: "https://flagcdn.com/us.svg",
// currency: "USD", dialCode: "+1" }
Detect flag from visitor's IP
Combine IP geolocation with the flag URL to show a visitor's flag in real time:
// One call gets country code — derive flag URL locally (no second call)
async function getVisitorFlag(): Promise<{ flag: string; countryName: string }> {
const res = await fetch(
`https://api.apogeoapi.com/v1/geo/self?apikey=${process.env.NEXT_PUBLIC_APOGEO_KEY}`
);
const geo = await res.json();
const flagUrl = `https://flagcdn.com/${geo.countryCode.toLowerCase()}.svg`;
return { flag: flagUrl, countryName: geo.countryName };
}
// React usage
function VisitorFlag() {
const [flag, setFlag] = useState<string | null>(null);
useEffect(() => {
getVisitorFlag().then(({ flag }) => setFlag(flag));
}, []);
return flag ? (
<img src={flag} alt="Your country" width={24} height={18} />
) : null;
}
Country selector with flags
// Full country list with flags from ApogeoAPI
async function getAllCountriesWithFlags() {
const res = await fetch(
`https://api.apogeoapi.com/v1/countries?apikey=${process.env.APOGEO_KEY}`
);
const countries = await res.json();
return countries.map((c: any) => ({
code: c.iso2,
name: c.commonName,
flag: c.flagUrl ?? `https://flagcdn.com/${c.iso2.toLowerCase()}.svg`,
dialCode: c.dialCode,
}));
}
// React select component
function CountrySelect({ onChange }) {
const [countries, setCountries] = useState([]);
useEffect(() => {
getAllCountriesWithFlags().then(setCountries);
}, []);
return (
<select onChange={e => onChange(e.target.value)} className="border rounded px-2 py-1">
{countries.map(c => (
<option key={c.code} value={c.code}>
{/* Emoji flag + country name */}
{countryCodeToEmoji(c.code)} {c.name}
</option>
))}
</select>
);
}
Performance tips
- Lazy-load flag images: Use
loading="lazy"on<img>tags — most visitors don't scroll to see every flag in a list - Cache country list: The full countries list changes rarely. Cache it in
localStoragewith a 24h TTL - Prefer emoji for single flag display: For showing just the visitor's country, emoji is 0-byte network overhead vs an SVG fetch
- Use CSS filter for greyscale:
filter: grayscale(100%)on inactive flags in a selector looks professional and reduces visual noise
Full API docs at api.apogeoapi.com/api/docs. Free tier at app.apogeoapi.com/register.
Try ApogeoAPI free
1,000 requests/month forever. 14-day full-access trial. No credit card.
Get your free API key