If you've ever wanted to pull live crypto prices into a Python script — without paying for an expensive data subscription — the CoinGecko API is your best starting point. It's free, well-documented, and doesn't require an API key for basic usage. In this tutorial, we'll go from zero to a working crypto data feed in about 30 minutes.
Prerequisites
Before we start, make sure you have:
- Python 3.8 or higher installed
- Basic Python knowledge (lists, loops,
printstatements) - An internet connection
That's it. No account required. No credit card. Just Python.
Why CoinGecko?
There are several crypto data providers out there — CryptoCompare, Messari, Binance's own API — but CoinGecko stands out for beginners because:
- No API key needed for most endpoints (free tier is generous)
- Massive coverage — 10,000+ coins tracked
- Clean, consistent JSON responses that are easy to parse
- Rate limits are reasonable — 10-30 calls/minute on the free tier
The only downside: real-time tick data isn't available for free. But for market scanning, portfolio tracking, and learning, it's more than enough.
Step 1: Your First API Request
Let's start simple. Open a Python file and fetch the current BTC price:
import urllib.request
import json
def get_price(coin_id: str, vs_currency: str = "usd") -> float:
"""Fetch the current price of a coin from CoinGecko."""
url = (
f"https://api.coingecko.com/api/v3/simple/price"
f"?ids={coin_id}&vs_currencies={vs_currency}"
)
with urllib.request.urlopen(url, timeout=10) as response:
data = json.loads(response.read().decode("utf-8"))
return data[coin_id][vs_currency]
# Test it
btc_price = get_price("bitcoin")
eth_price = get_price("ethereum")
print(f"BTC: ${btc_price:,.2f}")
print(f"ETH: ${eth_price:,.2f}")
Run it and you should see something like:
BTC: $67,423.00
ETH: $3,241.50
Step 2: Fetching Multiple Coins at Once
Instead of making one request per coin (which wastes your rate limit), batch them:
def get_prices(coin_ids: list, vs_currency: str = "usd") -> dict:
"""Fetch prices for multiple coins in a single request."""
ids_param = ",".join(coin_ids)
url = (
f"https://api.coingecko.com/api/v3/simple/price"
f"?ids={ids_param}&vs_currencies={vs_currency}"
f"&include_24hr_change=true&include_market_cap=true"
)
with urllib.request.urlopen(url, timeout=15) as response:
return json.loads(response.read().decode("utf-8"))
# Your watchlist
WATCHLIST = ["bitcoin", "ethereum", "solana", "chainlink", "cardano"]
prices = get_prices(WATCHLIST)
print(f"\n{'Coin':<12} {'Price':>12} {'24h Change':>12}")
print("-" * 40)
for coin_id, data in prices.items():
price = data.get("usd", 0)
change = data.get("usd_24h_change", 0)
arrow = "↑" if change > 0 else "↓"
print(f"{coin_id:<12} ${price:>11,.2f} {arrow}{abs(change):>9.2f}%")
Output:
Coin Price 24h Change
----------------------------------------
bitcoin $67,423.00 ↑2.34%
ethereum $3,241.50 ↑1.87%
solana $147.20 ↓0.45%
chainlink $13.87 ↑4.12%
cardano $0.42 ↓1.23%
Step 3: Building a Live Data Feed
Now let's make it continuously poll for price updates:
import time
import os
from datetime import datetime
def clear_screen():
os.system("cls" if os.name == "nt" else "clear")
def run_feed(watchlist: list, interval: int = 60):
"""
Live crypto price feed that refreshes every `interval` seconds.
Press Ctrl+C to stop.
"""
print(f"Starting crypto feed for: {', '.join(watchlist)}")
print(f"Refreshing every {interval} seconds. Press Ctrl+C to stop.\n")
while True:
try:
prices = get_prices(watchlist)
clear_screen()
now = datetime.now().strftime("%H:%M:%S")
print(f"Crypto Prices — Last updated: {now}")
print("=" * 50)
print(f"{'Coin':<12} {'Price':>12} {'24h':>10} {'Mkt Cap':>16}")
print("-" * 50)
for coin_id, data in prices.items():
price = data.get("usd", 0)
change = data.get("usd_24h_change", 0)
mcap = data.get("usd_market_cap", 0)
arrow = "+" if change >= 0 else ""
mcap_str = f"${mcap/1e9:.1f}B" if mcap > 1e9 else f"${mcap/1e6:.1f}M"
print(
f"{coin_id:<12} "
f"${price:>11,.2f} "
f"{arrow}{change:>8.2f}% "
f"{mcap_str:>16}"
)
print("=" * 50)
time.sleep(interval)
except KeyboardInterrupt:
print("\nFeed stopped.")
break
except Exception as e:
print(f"Error: {e}. Retrying in {interval}s...")
time.sleep(interval)
# Run it
WATCHLIST = ["bitcoin", "ethereum", "solana", "chainlink", "cardano"]
run_feed(WATCHLIST, interval=60)
Step 4: Working with Historical Data
Want to analyze trends or backtest a strategy? CoinGecko provides OHLCV (Open, High, Low, Close, Volume) data:
def get_ohlcv(coin_id: str, vs_currency: str = "usd", days: int = 30) -> list:
"""
Fetch OHLCV data for a coin.
Args:
coin_id: CoinGecko coin ID (e.g., "bitcoin")
vs_currency: Quote currency (e.g., "usd")
days: Number of days of history (1, 7, 14, 30, 90, 180, 365)
Returns:
List of [timestamp, open, high, low, close] lists
"""
url = (
f"https://api.coingecko.com/api/v3/coins/{coin_id}/ohlc"
f"?vs_currency={vs_currency}&days={days}"
)
with urllib.request.urlopen(url, timeout=15) as response:
data = json.loads(response.read().decode("utf-8"))
return data
# Fetch 30 days of BTC OHLCV
ohlcv = get_ohlcv("bitcoin", days=30)
print(f"Fetched {len(ohlcv)} candles")
print("\nLast 5 candles:")
print(f"{'Date':<20} {'Open':>10} {'High':>10} {'Low':>10} {'Close':>10}")
print("-" * 62)
for candle in ohlcv[-5:]:
ts, open_, high, low, close = candle
date = datetime.fromtimestamp(ts/1000).strftime("%Y-%m-%d %H:%M")
print(f"{date:<20} ${open_:>9,.0f} ${high:>9,.0f} ${low:>9,.0f} ${close:>9,.0f}")
Step 5: Smart Rate Limit Handling
CoinGecko's free tier allows about 10-30 requests per minute. Here's a simple rate limiter:
import time
from collections import deque
class RateLimiter:
"""Simple token bucket rate limiter."""
def __init__(self, calls_per_minute: int = 10):
self.calls_per_minute = calls_per_minute
self.min_interval = 60.0 / calls_per_minute
self.call_times = deque()
def wait_if_needed(self):
"""Block until it's safe to make another API call."""
now = time.time()
# Remove calls older than 1 minute
while self.call_times and now - self.call_times[0] > 60:
self.call_times.popleft()
# If at limit, wait
if len(self.call_times) >= self.calls_per_minute:
sleep_time = 60 - (now - self.call_times[0])
if sleep_time > 0:
time.sleep(sleep_time)
self.call_times.append(time.time())
# Usage
limiter = RateLimiter(calls_per_minute=8) # Stay under the limit
for coin in ["bitcoin", "ethereum", "solana"]:
limiter.wait_if_needed()
price = get_price(coin)
print(f"{coin}: ${price:,.2f}")
Step 6: Saving Data to CSV
Once you have data flowing, save it for later analysis:
import csv
from pathlib import Path
def save_to_csv(data: dict, filepath: str = "crypto_prices.csv"):
"""Append current price data to a CSV file."""
path = Path(filepath)
file_exists = path.exists()
now = datetime.now().isoformat()
with open(filepath, "a", newline="", encoding="utf-8") as f:
fieldnames = ["timestamp", "coin", "price_usd", "change_24h", "market_cap_usd"]
writer = csv.DictWriter(f, fieldnames=fieldnames)
if not file_exists:
writer.writeheader()
for coin_id, coin_data in data.items():
writer.writerow({
"timestamp": now,
"coin": coin_id,
"price_usd": coin_data.get("usd", 0),
"change_24h": coin_data.get("usd_24h_change", 0),
"market_cap_usd": coin_data.get("usd_market_cap", 0),
})
print(f"Saved {len(data)} coins to {filepath}")
# Use it
prices = get_prices(["bitcoin", "ethereum", "solana"])
save_to_csv(prices)
Step 7: Next Steps — Automate with OpenClaw
You now have a working crypto data feed. Here's where it gets interesting: you can turn this into a fully automated analysis agent using OpenClaw.
OpenClaw lets you run this kind of script as a local AI agent that:
- Monitors markets 24/7 without you being at the keyboard
- Detects patterns and sends you alerts
- Paper-trades automatically to test strategies safely
- Runs entirely on your own machine — no cloud, no subscription fees
The complete setup guide is available here: OpenClaw Home AI Agent Guide
Key Takeaways
- CoinGecko API is free for most use cases — no account needed
- Batch your requests — use comma-separated IDs to fetch multiple coins in one call
- Respect rate limits — 10 requests/minute is safe on the free tier
- OHLCV data is available for backtesting strategies
- Save to CSV to build your own historical dataset
- Automate it — run as a scheduled task or continuous loop for passive monitoring
The full code from this tutorial is available on request. Happy building!
Top comments (0)