If you've ever needed to pull country data into a project — flags, capitals, population numbers, currencies — you know how annoying it is to piece that together from multiple sources. The Countries Now API fixes that. It's free, requires no API key, and returns clean JSON for just about any country detail you'd want. Let's build something real with it.
Most developers hit this problem when building dashboards, travel apps, or educational tools. You need country info fast, and you don't want to manage authentication tokens or worry about rate limits every five minutes. That's exactly where a free country data API like Countries Now comes in handy.
By the end of this walkthrough, you'll have a working country info explorer built in Python. You'll fetch data like population, capital cities, currencies, and flags. You'll also handle errors properly so your app doesn't crash when something goes wrong.
What Is the Countries Now API?
Countries Now is a free, open REST API that gives you structured country data — no signup, no API key, no billing page. You just send a request and get back JSON. It covers things like population figures, country flags (as SVG URLs), currencies, cities, states, and more.
The base URL is https://countriesnow.space/api/v0.1. From there you hit different endpoints depending on what you need. Want the capital of France? There's an endpoint for that. Need a list of all cities in Germany? That too. It's a solid choice when you want a country API JavaScript example or a Python project without fighting OAuth flows.
Here's a quick overview of what it covers:
- Country capitals and flags
- Population data (historical and current)
- Currencies by country
- States and cities
- Country dial codes and ISO codes
Why Use This API?
There are a few country data APIs out there, but most either cost money or require registration. Countries Now is genuinely free — as in, you don't even create an account. For a beginner project or a quick prototype, that matters.
Here's why it works well for this kind of build:
- No API key needed — just make the request
- Returns consistent JSON structure
- Covers a wide range of data points
- Supports both GET and POST requests
- Works great for learning API integration basics
If you're building a country explorer app or teaching someone how APIs work, this is a clean starting point. The data is reliable enough for educational and prototyping purposes.
What You'll Need
Before writing any code, make sure you have Python 3.7 or above installed. You'll also need the requests library. If you don't have it yet, install it with:
pip install requests
That's it. No virtual environment setup required for this basic version, though it's always a good habit.
Step-by-Step: Building the Country Info Explorer
Step 1 — Fetch Basic Country Info
Start simple. Let's pull the capital for a given country. The Countries Now API uses POST requests for most lookups. You send a JSON body with the country name, and it returns structured data.
import requests
def get_country_capital(country_name):
url = "https://countriesnow.space/api/v0.1/countries/capital"
payload = {"country": country_name}
try:
response = requests.post(url, json=payload, timeout=10)
response.raise_for_status()
data = response.json()
if data.get("error"):
print(f"API error: {data.get('msg')}")
return None
return data["data"]
except requests.exceptions.Timeout:
print("Request timed out. Try again.")
return None
except requests.exceptions.RequestException as e:
print(f"Something went wrong: {e}")
return None
result = get_country_capital("Nigeria")
if result:
print(f"Country: {result['name']}")
print(f"Capital: {result['capital']}")
print(f"ISO Code: {result['iso2']}")
Run that and you'll see the capital of Nigeria printed out cleanly. The timeout=10 parameter is important — it stops your code from hanging forever if the API is slow.
Step 2 — Get Population Data
Population data is one of the more useful features here. You can get current population figures and even historical records. This is where the population data API free aspect really shines for data-driven projects.
def get_population(country_name):
url = "https://countriesnow.space/api/v0.1/countries/population"
payload = {"country": country_name}
try:
response = requests.post(url, json=payload, timeout=10)
response.raise_for_status()
data = response.json()
if data.get("error"):
print(f"API error: {data.get('msg')}")
return None
pop_data = data["data"]["populationCounts"]
latest = pop_data[-1] # Most recent entry
return {
"country": data["data"]["country"],
"year": latest["year"],
"population": latest["value"]
}
except requests.exceptions.ConnectionError:
print("Can't connect. Check your internet connection.")
return None
except (KeyError, IndexError) as e:
print(f"Unexpected response structure: {e}")
return None
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
pop = get_population("Brazil")
if pop:
print(f"{pop['country']} population ({pop['year']}): {pop['population']:}")
The pop_data[-1] grabs the last item in the list, which is the most recent year available. You'll get something like "Brazil population (2018): 209,469,333" depending on the data available.
Step 3 — Get Currency Information
Need to know what currency a country uses? There's an endpoint for that too. Here's how to fetch it cleanly:
def get_currency(country_name):
url = "https://countriesnow.space/api/v0.1/countries/currency"
payload = {"country": country_name}
try:
response = requests.post(url, json=payload, timeout=10)
response.raise_for_status()
data = response.json()
if data.get("error"):
return None
return data["data"]
except requests.exceptions.RequestException as e:
print(f"Request error: {e}")
return None
currency = get_currency("Japan")
if currency:
print(f"Currency: {currency['currency']}")
print(f"Symbol: {currency['symbol']}")
Step 4 — Build the Full Explorer Function
Now pull it all together into one clean explorer function. This is your actual build country explorer app running end to end.
def explore_country(country_name):
print(f"\n=== Country Info: {country_name} ===\n")
# Capital
capital_data = get_country_capital(country_name)
if capital_data:
print(f"Capital: {capital_data['capital']}")
print(f"ISO2: {capital_data['iso2']}")
print(f"ISO3: {capital_data['iso3']}")
# Population
pop_data = get_population(country_name)
if pop_data:
print(f"Population: {pop_data['population']:} ({pop_data['year']})")
# Currency
currency_data = get_currency(country_name)
if currency_data:
print(f"Currency: {currency_data['currency']} ({currency_data['symbol']})")
print("\n--- Done ---\n")
# Test it out
explore_country("Germany")
explore_country("Canada")
explore_country("Kenya")
That's your countries now api tutorial working from start to finish. Each function handles its own errors, so if one call fails, the others still run without breaking the whole script.
Understanding the Output
When you run explore_country("Germany"), you should see something like this:
=== Country Info: Germany ===
Capital: Berlin
ISO2: DE
ISO3: DEU
Population: 83,132,799 (2018)
Currency: Euro (€)
--- Done ---
The API returns nested JSON objects. Each endpoint has a slightly different structure, which is why we access different keys in each function. The data key is the main payload — everything useful sits inside it.
Error Handling
You already saw try/except blocks in each function. Here's a breakdown of the main error types you'll run into:
- requests.exceptions.Timeout — The server took too long. Always set a timeout.
- requests.exceptions.ConnectionError — No internet or DNS issues.
- requests.exceptions.HTTPError — A 4xx or 5xx status code from the server.
- KeyError / IndexError — The JSON structure wasn't what you expected. This happens when the API returns an error message instead of data.
One thing to watch for: Countries Now sometimes returns "error": true in the response body even with a 200 HTTP status. Always check data.get("error") before touching the data keys. Here's a reusable helper that wraps all of this:
def safe_post(url, payload):
try:
response = requests.post(url, json=payload, timeout=10)
response.raise_for_status()
data = response.json()
if data.get("error"):
print(f"API returned error: {data.get('msg', 'Unknown error')}")
return None
return data.get("data")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
Swap safe_post into any of the earlier functions and you'll cut down on a lot of repeated code.
Real-World Use Cases
So where does something like this actually get used? More places than you'd think.
- Travel planning apps — Show users the currency and capital before they book a trip.
- Educational dashboards — Geography quizzes, world maps with clickable country details.
- E-commerce checkout flows — Auto-fill currency and country info based on a user's selected shipping destination.
- Data journalism tools — Pull population figures to visualize demographic trends over time.
- Admin panels — Country dropdowns that auto-populate related fields when a country is selected.
Anywhere you need structured country data without a heavy backend, this free country data API gets the job done without friction.
Countries Now API vs Other Free Options
| API | Free Tier | API Key Required | Population Data | Cities/States |
|---|---|---|---|---|
| Countries Now | Fully free | No | Yes | Yes |
| RestCountries | Fully free | No | Yes | No |
| GeoNames | Free with limits | Yes | Yes | Yes |
| World Bank API | Fully free | No | Yes | No |
Countries Now stands out because it includes cities and states data without any registration. RestCountries is also solid for basic info. If you need deeper geographic data, GeoNames is worth signing up for — but for a quick build, Countries Now is the right call.
Frequently Asked Questions
Is the Countries Now API actually free?
Yes, completely. No signup, no API key, no credit card. You make HTTP requests straight to the base URL. It's one of the few genuinely free country data APIs that works right out of the box.
Does the Countries Now API have rate limits?
Rate limits aren't officially documented, but it's good practice to add delays between bulk requests. If you're looping through hundreds of countries, add a time.sleep(0.5) between calls to avoid hammering the server.
Can I use this for a country API JavaScript example?
Absolutely. The API works with any language that can make HTTP requests. In JavaScript, use fetch() with a POST method and a JSON body. The response format is exactly the same as in Python.
Why does my country name not return results?
Spelling matters a lot here. Use the full English country name — "United States" not "USA", "United Kingdom" not "UK". If you're unsure, first call the /countries GET endpoint to see the complete list of accepted country names.
Can I get a list of all countries at once?
Yes. Send a GET request to https://countriesnow.space/api/v0.1/countries and you'll get back every country along with its cities. It's a large response, so make sure you parse and filter it carefully.
Is the population data up to date?
The population data comes from World Bank records and typically runs up to 2018 or 2019. It's not real-time data, but it's accurate enough for educational tools, dashboards, and most prototyping work.
Conclusion
The Countries Now API is one of those tools that just works. No auth headaches, clean JSON, and enough data points to build something genuinely useful. You've now got a working Python country explorer that fetches capitals, population figures, and currency data — all with solid error handling built in.
From here, you could extend this by adding a simple web front-end with Flask, connecting it to a database to cache results, or pairing it with a mapping library like Folium to put the data on an actual map. The foundation is there — what you build on top of it is up to you.
Want more tutorials like this? Browse the Free API Hub for guides on other no-key, beginner-friendly APIs you can start using right now. Every tutorial includes real, working code and clear explanations — nothing padded, nothing skipped.










