// Get emergency numbers for Japan
const response = await fetch("https://worlddataapi.com/v1/travel/JP", {
headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await response.json();
console.log(data.emergency);
// {
// "police": "110",
// "fire": "119",
// "ambulance": "119"
// }
In an emergency abroad, the last thing you want is to discover that 911 doesn't work. Emergency numbers vary worldwide: Japan uses 110 for police and 119 for fire/ambulance. The UK uses 999. The EU standardized on 112. This guide covers building a feature that gives travelers instant access to the right numbers.
The Challenge#
Hardcoding emergency numbers seems straightforward until you consider the scope:
249 countries with different emergency systems
Multiple number types (police, fire, ambulance) that may or may not be unified
No universal standard despite 112 becoming more common
Critical reliability requirements since this feature must work when users need it most
Offline access because emergencies don't wait for network connectivity
The World Data API provides national-level emergency numbers for all countries, giving you a single endpoint to query instead of maintaining your own database.
Note: Emergency number data is available at the national level only. Some countries have regional variations that are not captured in the API.
Prerequisites#
Before starting, you need:
A World Data API key (sign up for free)
Basic knowledge of JavaScript/React or Python
Understanding of REST APIs and async/await patterns
Emergency Numbers Vary Widely#
Some examples of how emergency numbers differ:
| Country | Police | Fire | Ambulance |
|---|---|---|---|
| United States | 911 | 911 | 911 |
| United Kingdom | 999 | 999 | 999 |
| Japan | 110 | 119 | 119 |
| Australia | 000 | 000 | 000 |
| European Union | 112 | 112 | 112 |
| India | 100 | 101 | 102 |
| China | 110 | 119 | 120 |
| Brazil | 190 | 193 | 192 |
Notice that:
Some countries use a single number for all emergencies
Some have different numbers for each service
Fire and ambulance often share a number (separate from police)
Basic Implementation#
curl#
curl -X GET "https://worlddataapi.com/v1/travel/JP" \
-H "X-API-Key: YOUR_API_KEY"
Python#
import requests
def get_emergency_numbers(country: str, api_key: str) -> dict:
response = requests.get(
f"https://worlddataapi.com/v1/travel/{country}",
headers={"X-API-Key": api_key}
)
response.raise_for_status()
data = response.json()
return {
"country": data["destination"],
"emergency": data["emergency"],
"phone_code": data["phone_code"],
}
# Usage
japan = get_emergency_numbers("JP", "YOUR_API_KEY")
print(japan)
# {
# "country": "JP",
# "emergency": {"police": "110", "fire": "119", "ambulance": "119"},
# "phone_code": "+81"
# }
JavaScript#
async function getEmergencyNumbers(country) {
const response = await fetch(
`https://worlddataapi.com/v1/travel/${country}`,
{ headers: { "X-API-Key": API_KEY } },
);
const data = await response.json();
return {
country: data.destination,
emergency: data.emergency,
phoneCode: data.phone_code,
};
}
// Usage
const japan = await getEmergencyNumbers("JP");
console.log(japan);
// {
// country: "JP",
// emergency: { police: "110", fire: "119", ambulance: "119" },
// phoneCode: "+81"
// }
Building the UI#
Create a quick-access emergency panel:
function EmergencyNumbers({ country }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
getEmergencyNumbers(country)
.then(setData)
.finally(() => setLoading(false));
}, [country]);
if (loading)
return <div className="loading">Loading emergency info...</div>;
if (!data)
return <div className="error">Could not load emergency numbers</div>;
const { emergency } = data;
return (
<div className="emergency-panel">
<h2>Emergency Numbers</h2>
<p className="location">{getCountryName(country)}</p>
<div className="emergency-numbers">
<EmergencyButton
icon="police"
label="Police"
number={emergency.police}
/>
<EmergencyButton
icon="fire"
label="Fire"
number={emergency.fire}
/>
<EmergencyButton
icon="ambulance"
label="Ambulance"
number={emergency.ambulance}
/>
</div>
</div>
);
}
function EmergencyButton({ icon, label, number }) {
const handleCall = () => {
// On mobile, this opens the phone dialer
window.location.href = `tel:${number}`;
};
return (
<button
className="emergency-button"
onClick={handleCall}
aria-label={`Call ${label}: ${number}`}
>
<span className={`icon icon-${icon}`} aria-hidden="true" />
<span className="label">{label}</span>
<span className="number">{number}</span>
</button>
);
}
Offline Support#
Emergency numbers must work without an internet connection. Cache them aggressively:
const EMERGENCY_CACHE_KEY = "emergency_numbers_cache";
class EmergencyCache {
constructor() {
this.cache = this.loadFromStorage();
}
loadFromStorage() {
try {
const stored = localStorage.getItem(EMERGENCY_CACHE_KEY);
return stored ? JSON.parse(stored) : {};
} catch {
return {};
}
}
saveToStorage() {
try {
localStorage.setItem(
EMERGENCY_CACHE_KEY,
JSON.stringify(this.cache),
);
} catch (e) {
console.warn("Could not save emergency cache:", e);
}
}
async get(country) {
// Always return cached data if available
if (this.cache[country]) {
// Try to refresh in background, but return cached immediately
this.refresh(country).catch(() => {});
return this.cache[country];
}
// No cache — must fetch
return this.refresh(country);
}
async refresh(country) {
try {
const data = await getEmergencyNumbers(country);
this.cache[country] = data;
this.saveToStorage();
return data;
} catch (e) {
// If refresh fails but we have cached data, return it
if (this.cache[country]) {
return this.cache[country];
}
throw e;
}
}
// Preload countries the user might visit
async preload(countries) {
await Promise.allSettled(
countries.map((country) => this.refresh(country)),
);
}
}
const emergencyCache = new EmergencyCache();
Service Worker Caching#
For true offline support, use a service worker:
// sw.js - Service Worker
const CACHE_NAME = "emergency-v1";
const EMERGENCY_API_PATTERN = /worlddataapi\.com\/v1\/travel\//;
self.addEventListener("fetch", (event) => {
const { request } = event;
// Special handling for emergency data
if (EMERGENCY_API_PATTERN.test(request.url)) {
event.respondWith(cacheFirst(request));
}
});
async function cacheFirst(request) {
const cache = await caches.open(CACHE_NAME);
// Try cache first
const cached = await cache.match(request);
if (cached) {
// Return cached, but refresh in background
refreshCache(request, cache);
return cached;
}
// Not in cache — fetch and cache
try {
const response = await fetch(request);
if (response.ok) {
cache.put(request, response.clone());
}
return response;
} catch (error) {
// Network failed, no cache — return error response
return new Response(
JSON.stringify({ error: "Offline and no cached data" }),
{ status: 503, headers: { "Content-Type": "application/json" } },
);
}
}
async function refreshCache(request, cache) {
try {
const response = await fetch(request);
if (response.ok) {
cache.put(request, response.clone());
}
} catch {
// Refresh failed — keep existing cache
}
}
Hardcoded Fallback#
For critical features like emergency numbers, include a hardcoded fallback in case both network and cache fail:
const FALLBACK_EMERGENCY = {
US: { police: "911", fire: "911", ambulance: "911" },
GB: { police: "999", fire: "999", ambulance: "999" },
EU: { police: "112", fire: "112", ambulance: "112" }, // Works in all EU countries
JP: { police: "110", fire: "119", ambulance: "119" },
AU: { police: "000", fire: "000", ambulance: "000" },
CN: { police: "110", fire: "119", ambulance: "120" },
IN: { police: "100", fire: "101", ambulance: "102" },
// Add more as needed
};
async function getEmergencyNumbersSafe(country) {
try {
return await emergencyCache.get(country);
} catch (error) {
// API and cache both failed — use fallback
const fallback =
FALLBACK_EMERGENCY[country] || FALLBACK_EMERGENCY["EU"];
return {
country,
emergency: fallback,
isFallback: true,
};
}
}
EU 112 Awareness#
112 works across all EU countries and increasingly worldwide:
function EmergencyPanel({ country }) {
const [data, setData] = useState(null);
const isEU = EU_COUNTRIES.includes(country);
return (
<div className="emergency-panel">
<EmergencyNumbers data={data} />
{isEU && (
<div className="eu-notice">
<strong>Tip:</strong> 112 works across all EU countries. It
connects you to emergency services and operators often speak
English.
</div>
)}
</div>
);
}
const EU_COUNTRIES = [
"AT",
"BE",
"BG",
"HR",
"CY",
"CZ",
"DK",
"EE",
"FI",
"FR",
"DE",
"GR",
"HU",
"IE",
"IT",
"LV",
"LT",
"LU",
"MT",
"NL",
"PL",
"PT",
"RO",
"SK",
"SI",
"ES",
"SE",
];
Language Considerations#
Emergency operators may not speak English. Help users prepare:
function EmergencyPrep({ country }) {
const phrases = EMERGENCY_PHRASES[country] || EMERGENCY_PHRASES["default"];
return (
<div className="emergency-prep">
<h3>Useful Phrases</h3>
<ul>
<li>
<strong>Help!</strong>
<span className="local">{phrases.help}</span>
</li>
<li>
<strong>I need police</strong>
<span className="local">{phrases.police}</span>
</li>
<li>
<strong>I need an ambulance</strong>
<span className="local">{phrases.ambulance}</span>
</li>
<li>
<strong>There's a fire</strong>
<span className="local">{phrases.fire}</span>
</li>
</ul>
<p className="tip">
Consider saving these phrases offline or taking a screenshot.
</p>
</div>
);
}
const EMERGENCY_PHRASES = {
JP: {
help: "Tasukete! (助けて)",
police: "Keisatsu wo yonde kudasai (警察を呼んでください)",
ambulance: "Kyuukyuusha wo yonde kudasai (救急車を呼んでください)",
fire: "Kaji desu (火事です)",
},
DE: {
help: "Hilfe!",
police: "Ich brauche die Polizei",
ambulance: "Ich brauche einen Krankenwagen",
fire: "Es brennt!",
},
FR: {
help: "Au secours!",
police: "J'ai besoin de la police",
ambulance: "J'ai besoin d'une ambulance",
fire: "Il y a un incendie!",
},
ES: {
help: "¡Socorro!",
police: "Necesito la policía",
ambulance: "Necesito una ambulancia",
fire: "¡Hay un incendio!",
},
default: {
help: "Help!",
police: "I need police",
ambulance: "I need an ambulance",
fire: "There's a fire",
},
};
Prominent Display#
Emergency info should be immediately accessible:
function TravelApp() {
const [currentCountry, setCurrentCountry] = useState("JP");
return (
<div className="travel-app">
{/* Emergency should be easily findable */}
<header>
<nav>
<Link to="/itinerary">Itinerary</Link>
<Link to="/emergency" className="emergency-link">
Emergency
</Link>
</nav>
</header>
{/* Also show inline on relevant pages */}
<main>
<CountryOverview country={currentCountry} />
<EmergencyQuickAccess country={currentCountry} />
</main>
</div>
);
}
function EmergencyQuickAccess({ country }) {
const [expanded, setExpanded] = useState(false);
const [data, setData] = useState(null);
useEffect(() => {
getEmergencyNumbersSafe(country).then(setData);
}, [country]);
if (!data) return null;
return (
<div className="emergency-quick-access">
<button
className="toggle"
onClick={() => setExpanded(!expanded)}
aria-expanded={expanded}
>
Emergency Numbers
<span className="chevron">{expanded ? "^" : "v"}</span>
</button>
{expanded && (
<div className="numbers">
<a href={`tel:${data.emergency.police}`} className="number">
Police: {data.emergency.police}
</a>
<a
href={`tel:${data.emergency.ambulance}`}
className="number"
>
Ambulance: {data.emergency.ambulance}
</a>
<a href={`tel:${data.emergency.fire}`} className="number">
Fire: {data.emergency.fire}
</a>
</div>
)}
</div>
);
}
Additional Emergency Information#
Beyond numbers, provide context:
function ComprehensiveEmergency({ country }) {
const [data, setData] = useState(null);
return (
<div className="comprehensive-emergency">
<EmergencyNumbers data={data} />
<section className="additional-info">
<h3>Before an Emergency</h3>
<ul>
<li>Save emergency numbers in your phone contacts</li>
<li>Know your hotel/accommodation address</li>
<li>
Keep a copy of your passport separately from the
original
</li>
<li>Note your country's embassy location and phone</li>
</ul>
<h3>When Calling</h3>
<ul>
<li>Stay calm and speak clearly</li>
<li>State your emergency type: police, fire, or medical</li>
<li>Give your exact location (address or landmarks)</li>
<li>Follow the operator's instructions</li>
<li>Don't hang up until told to do so</li>
</ul>
</section>
<EmbassyInfo country={country} />
</div>
);
}
function EmbassyInfo({ country }) {
// You might want to let users set their home country
const [userNationality, setUserNationality] = useState("US");
return (
<div className="embassy-info">
<h3>Your Country's Embassy</h3>
<p>
If you lose your passport or need consular assistance, contact
your country's embassy or consulate.
</p>
<a
href={`https://www.embassy-worldwide.com/${country}/${userNationality}`}
target="_blank"
rel="noopener noreferrer"
>
Find {getCountryName(userNationality)} Embassy in{" "}
{getCountryName(country)}
</a>
</div>
);
}
Multi-Destination Trips#
For travelers visiting multiple countries:
function TripEmergencyCard({ destinations }) {
const [emergencyData, setEmergencyData] = useState({});
useEffect(() => {
Promise.all(
destinations.map(async (d) => ({
country: d,
data: await getEmergencyNumbersSafe(d),
})),
).then((results) => {
const data = {};
results.forEach((r) => {
data[r.country] = r.data;
});
setEmergencyData(data);
});
}, [destinations]);
return (
<div className="trip-emergency-card">
<h2>Emergency Numbers for Your Trip</h2>
<p className="tip">
Take a screenshot of this card for offline access
</p>
<div className="countries">
{destinations.map((country) => (
<div key={country} className="country-block">
<h3>{getCountryName(country)}</h3>
{emergencyData[country] && (
<div className="numbers-compact">
<span>
Police:{" "}
{emergencyData[country].emergency.police}
</span>
<span>
Ambulance:{" "}
{emergencyData[country].emergency.ambulance}
</span>
<span>
Fire:{" "}
{emergencyData[country].emergency.fire}
</span>
</div>
)}
</div>
))}
</div>
</div>
);
}
Styling#
.emergency-panel {
background: #fff5f5;
border: 2px solid #dc3545;
border-radius: 8px;
padding: 20px;
}
.emergency-panel h2 {
color: #dc3545;
margin-top: 0;
}
.emergency-numbers {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 16px;
margin-top: 16px;
}
.emergency-button {
display: flex;
flex-direction: column;
align-items: center;
padding: 16px;
background: white;
border: 2px solid #dc3545;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
}
.emergency-button:hover {
background: #dc3545;
color: white;
}
.emergency-button:active {
transform: scale(0.98);
}
.emergency-button .icon {
font-size: 32px;
margin-bottom: 8px;
}
.emergency-button .label {
font-size: 14px;
color: #666;
}
.emergency-button:hover .label {
color: rgba(255, 255, 255, 0.8);
}
.emergency-button .number {
font-size: 24px;
font-weight: bold;
color: #dc3545;
}
.emergency-button:hover .number {
color: white;
}
.emergency-quick-access {
background: #fff;
border: 1px solid #dc3545;
border-radius: 8px;
overflow: hidden;
}
.emergency-quick-access .toggle {
width: 100%;
padding: 12px 16px;
background: #fff5f5;
border: none;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
font-weight: 500;
color: #dc3545;
}
.emergency-quick-access .numbers {
padding: 16px;
display: flex;
flex-direction: column;
gap: 8px;
}
.emergency-quick-access .number {
display: block;
padding: 8px 12px;
background: #f8f9fa;
border-radius: 4px;
text-decoration: none;
color: #333;
}
.emergency-quick-access .number:hover {
background: #e9ecef;
}
.eu-notice {
margin-top: 16px;
padding: 12px;
background: #e7f3ff;
border-radius: 4px;
font-size: 14px;
}
.trip-emergency-card {
background: white;
border: 2px solid #dc3545;
border-radius: 8px;
padding: 20px;
}
.trip-emergency-card .tip {
background: #fff3cd;
padding: 8px 12px;
border-radius: 4px;
font-size: 14px;
}
.trip-emergency-card .countries {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
margin-top: 16px;
}
.trip-emergency-card .country-block {
padding: 12px;
background: #f8f9fa;
border-radius: 4px;
}
.trip-emergency-card .numbers-compact {
display: flex;
flex-wrap: wrap;
gap: 8px;
font-size: 14px;
}
Common Pitfalls#
Assuming 911 works everywhere. Many developers hardcode 911 as a fallback. This can be dangerous in countries where 911 does not connect to emergency services.
Not caching aggressively enough. Emergency numbers rarely change. Cache them for weeks or months, not hours. A stale emergency number is better than no emergency number when the user is offline.
Forgetting about regional variations. The API provides national-level numbers, but some countries have regional variations. Consider adding a disclaimer to your UI noting that local numbers may differ.
Making the feature hard to find. Emergency info should be accessible within one or two taps from anywhere in your app. Do not bury it in settings.
Not testing offline scenarios. Verify your app displays emergency numbers when the device has no network connectivity. This is the most critical use case.
Over-relying on the API for fallback data. Include hardcoded fallback numbers for major travel destinations in your app bundle. API failures during an emergency are unacceptable.
Summary#
Emergency numbers vary by country, and travelers need instant access to the right numbers. The World Data API provides national-level emergency contact data for 249 countries through a single endpoint.
Key implementation points:
Query the
/v1/travel/{country}endpoint for police, fire, and ambulance numbersCache responses aggressively and implement offline support
Include hardcoded fallback data for major destinations
Make emergency information prominent and accessible within your app
Consider adding local language phrases and EU 112 awareness
Ready to add emergency numbers to your travel app? Get your free API key and start building today.
Next Steps#
Building a Power Adapter Checker for Travel Apps — Another travel essential
Building a Trip Planning Feature with Climate Data — Weather-based planning
Caching Strategies for Reference Data APIs — Offline-first patterns