Adding Emergency Numbers to Your Travel App

javascript
// 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:

CountryPoliceFireAmbulance
United States911911911
United Kingdom999999999
Japan110119119
Australia000000000
European Union112112112
India100101102
China110119120
Brazil190193192

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#

bash
curl -X GET "https://worlddataapi.com/v1/travel/JP" \
  -H "X-API-Key: YOUR_API_KEY"

Python#

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#

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:

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

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

javascript
// 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:

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

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

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

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

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

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

css
.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 numbers

  • Cache 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#