JavaScript Oil Price API
Integrate real-time oil and commodity prices into your JavaScript applications. Works with Node.js, React, Vue, Angular, and vanilla JavaScript.
Quick Start
1. Install Dependencies (Optional)
npm install axios
npm install node-cache # for Node.js caching
npm install express cors # for Node.js server
2. Get Your API Key
- Works in browser and Node.js
- No additional dependencies required
- 30,000 free requests/month
Basic Integration
// Basic JavaScript integration with fetch API
class OilPriceAPI {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.oilpriceapi.com';
this.headers = {
'Authorization': `Token ${apiKey}`,
'Content-Type': 'application/json'
};
}
async getBrentPrice() {
try {
const response = await fetch(`${this.baseUrl}/prices`, {
headers: this.headers
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Error fetching Brent price:', error);
throw error;
}
}
async getCommodityHealth() {
try {
const response = await fetch(`${this.baseUrl}/health`, {
headers: this.headers
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Error fetching commodity health:', error);
throw error;
}
}
async getWTIPrice() {
try {
const healthData = await this.getCommodityHealth();
const wtiData = healthData.metrics?.commodity_health?.WTI_USD;
if (wtiData) {
return {
price: wtiData.latest_price / 100, // Convert from cents
timestamp: wtiData.last_update,
currency: 'USD',
unit: 'barrel'
};
}
return null;
} catch (error) {
console.error('Error fetching WTI price:', error);
throw error;
}
}
async getAllCommodities() {
try {
const [brentResponse, healthResponse] = await Promise.all([
this.getBrentPrice(),
this.getCommodityHealth()
]);
const commodities = {
brent: {
price: brentResponse.data.price,
timestamp: brentResponse.data.timestamp
}
};
const healthData = healthResponse.metrics?.commodity_health || {};
// Extract other commodities from health data
Object.entries(healthData).forEach(([key, data]) => {
if (data.latest_price) {
const scale = key.includes('EUR_USD') || key.includes('GBP_USD') ? 10000 : 100;
commodities[key.toLowerCase()] = {
price: data.latest_price / scale,
timestamp: data.last_update
};
}
});
return commodities;
} catch (error) {
console.error('Error fetching all commodities:', error);
throw error;
}
}
}
// Usage example
const api = new OilPriceAPI('YOUR_API_KEY_HERE');
// Get individual prices
api.getBrentPrice()
.then(data => console.log('Brent:', data.data.price))
.catch(error => console.error('Error:', error));
// Get all commodities
api.getAllCommodities()
.then(commodities => {
console.log('All commodities:', commodities);
})
.catch(error => console.error('Error:', error));
React Integration
Complete React component with custom hook for state management:
import React, { useState, useEffect } from 'react';
// Custom hook for oil price data
function useOilPrices(apiKey) {
const [prices, setPrices] = useState({});
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const api = new OilPriceAPI(apiKey);
const fetchPrices = async () => {
try {
setLoading(true);
const commodities = await api.getAllCommodities();
setPrices(commodities);
setError(null);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchPrices();
// Update every 5 minutes
const interval = setInterval(fetchPrices, 5 * 60 * 1000);
return () => clearInterval(interval);
}, [apiKey]);
return { prices, loading, error };
}
// React component for displaying oil prices
function OilPriceDashboard({ apiKey }) {
const { prices, loading, error } = useOilPrices(apiKey);
if (loading) {
return (
<div className="flex items-center justify-center p-8">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
<span className="ml-2">Loading prices...</span>
</div>
);
}
if (error) {
return (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
<strong>Error:</strong> {error}
</div>
);
}
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{Object.entries(prices).map(([commodity, data]) => (
<div key={commodity} className="bg-white border border-gray-200 rounded-lg p-4 shadow">
<h3 className="font-semibold text-lg capitalize mb-2">
{commodity.replace('_', ' ')}
</h3>
<div className="text-2xl font-bold text-blue-600">
${typeof data.price === 'number' ? data.price.toFixed(2) : data.price}
</div>
<div className="text-sm text-gray-500 mt-1">
Updated: {new Date(data.timestamp).toLocaleTimeString()}
</div>
</div>
))}
</div>
);
}
// Usage in your React app
function App() {
return (
<div className="p-8">
<h1 className="text-3xl font-bold mb-8">Live Oil Prices</h1>
<OilPriceDashboard apiKey="YOUR_API_KEY_HERE" />
</div>
);
}
export default App;
Node.js Server
Express server with caching and error handling:
// Node.js server implementation with Express
const express = require('express');
const cors = require('cors');
const NodeCache = require('node-cache');
const app = express();
const cache = new NodeCache({ stdTTL: 300 }); // 5 minute cache
app.use(cors());
app.use(express.json());
class OilPriceService {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.oilpriceapi.com';
this.headers = {
'Authorization': `Token ${apiKey}`,
'Content-Type': 'application/json'
};
}
async fetchWithTimeout(url, options, timeout = 5000) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
clearTimeout(id);
return response;
} catch (error) {
clearTimeout(id);
throw error;
}
}
async getBrentPrice() {
const response = await this.fetchWithTimeout(
`${this.baseUrl}/prices`,
{ headers: this.headers }
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
}
async getCommodityHealth() {
const response = await this.fetchWithTimeout(
`${this.baseUrl}/health`,
{ headers: this.headers }
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
}
async getAllPrices() {
try {
const [brentData, healthData] = await Promise.all([
this.getBrentPrice(),
this.getCommodityHealth()
]);
const prices = {
brent_crude: {
price: brentData.data.price,
timestamp: brentData.data.timestamp,
unit: 'barrel'
}
};
const commodities = healthData.metrics?.commodity_health || {};
// Process each commodity
Object.entries(commodities).forEach(([key, data]) => {
if (data.latest_price) {
let scale = 100;
if (key.includes('EUR_USD') || key.includes('GBP_USD')) {
scale = 10000; // Currency pairs
}
prices[key.toLowerCase()] = {
price: data.latest_price / scale,
timestamp: data.last_update,
unit: this.getUnit(key)
};
}
});
return {
status: 'success',
data: prices,
cached_at: new Date().toISOString()
};
} catch (error) {
throw new Error(`Failed to fetch prices: ${error.message}`);
}
}
getUnit(commodityKey) {
const units = {
'WTI_USD': 'barrel',
'NATURAL_GAS_USD': 'MMBtu',
'GOLD_USD': 'ounce',
'EUR_USD': 'USD',
'GBP_USD': 'USD'
};
return units[commodityKey] || 'unit';
}
}
// Initialize service
const priceService = new OilPriceService(process.env.OIL_PRICE_API_KEY);
// Middleware to ensure API key is set
const requireApiKey = (req, res, next) => {
if (!process.env.OIL_PRICE_API_KEY) {
return res.status(500).json({
error: 'API key not configured'
});
}
next();
};
// Routes
app.get('/api/prices', requireApiKey, async (req, res) => {
try {
// Check cache first
const cachedPrices = cache.get('all_prices');
if (cachedPrices) {
return res.json({
...cachedPrices,
cached: true
});
}
// Fetch fresh data
const prices = await priceService.getAllPrices();
// Cache the results
cache.set('all_prices', prices);
res.json(prices);
} catch (error) {
console.error('Error fetching prices:', error);
res.status(500).json({
status: 'error',
message: error.message
});
}
});
app.get('/api/prices/:commodity', requireApiKey, async (req, res) => {
try {
const { commodity } = req.params;
// Get all prices (from cache or API)
let allPrices = cache.get('all_prices');
if (!allPrices) {
allPrices = await priceService.getAllPrices();
cache.set('all_prices', allPrices);
}
const commodityData = allPrices.data[commodity.toLowerCase()];
if (!commodityData) {
return res.status(404).json({
status: 'error',
message: `Commodity '${commodity}' not found`
});
}
res.json({
status: 'success',
commodity: commodity,
data: commodityData
});
} catch (error) {
console.error('Error fetching commodity price:', error);
res.status(500).json({
status: 'error',
message: error.message
});
}
});
app.get('/health', (req, res) => {
const cacheKeys = cache.keys();
res.json({
status: 'healthy',
cache_entries: cacheKeys.length,
uptime: process.uptime(),
memory_usage: process.memoryUsage()
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Vue.js Component
Vue 3 component with Composition API:
<!-- Vue.js component for oil prices -->
<template>
<div class="oil-prices-dashboard">
<div class="header">
<h1>Live Oil Prices</h1>
<div class="last-updated" v-if="lastUpdated">
Last updated: {{ formatTime(lastUpdated) }}
</div>
</div>
<div v-if="loading" class="loading">
<div class="spinner"></div>
<p>Loading prices...</p>
</div>
<div v-if="error" class="error">
<p>{{ error }}</p>
<button @click="fetchPrices" class="retry-btn">Retry</button>
</div>
<div v-if="!loading && !error" class="prices-grid">
<div
v-for="(data, commodity) in prices"
:key="commodity"
class="price-card"
:class="{ 'price-updated': recentlyUpdated.includes(commodity) }"
>
<h3>{{ formatCommodityName(commodity) }}</h3>
<div class="price">
${{ formatPrice(data.price) }}
</div>
<div class="unit">{{ data.unit }}</div>
<div class="timestamp">
{{ formatTime(data.timestamp) }}
</div>
</div>
</div>
</div>
</template>
<script>
import { ref, onMounted, onUnmounted } from 'vue';
export default {
name: 'OilPricesDashboard',
props: {
apiKey: {
type: String,
required: true
}
},
setup(props) {
const prices = ref({});
const loading = ref(true);
const error = ref(null);
const lastUpdated = ref(null);
const recentlyUpdated = ref([]);
let updateInterval = null;
class OilPriceAPI {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.oilpriceapi.com';
this.headers = {
'Authorization': `Token ${apiKey}`,
'Content-Type': 'application/json'
};
}
async getAllCommodities() {
try {
const [brentResponse, healthResponse] = await Promise.all([
fetch(`${this.baseUrl}/prices`, { headers: this.headers }),
fetch(`${this.baseUrl}/health`, { headers: this.headers })
]);
if (!brentResponse.ok || !healthResponse.ok) {
throw new Error('Failed to fetch data');
}
const brentData = await brentResponse.json();
const healthData = await healthResponse.json();
const commodities = {
brent_crude: {
price: brentData.data.price,
timestamp: brentData.data.timestamp,
unit: 'barrel'
}
};
const healthCommodities = healthData.metrics?.commodity_health || {};
Object.entries(healthCommodities).forEach(([key, data]) => {
if (data.latest_price) {
const scale = key.includes('EUR_USD') || key.includes('GBP_USD') ? 10000 : 100;
commodities[key.toLowerCase()] = {
price: data.latest_price / scale,
timestamp: data.last_update,
unit: this.getUnit(key)
};
}
});
return commodities;
} catch (err) {
throw new Error(`API Error: ${err.message}`);
}
}
getUnit(key) {
const units = {
'WTI_USD': 'barrel',
'NATURAL_GAS_USD': 'MMBtu',
'GOLD_USD': 'ounce',
'EUR_USD': 'USD',
'GBP_USD': 'USD'
};
return units[key] || 'unit';
}
}
const api = new OilPriceAPI(props.apiKey);
const fetchPrices = async () => {
try {
loading.value = true;
error.value = null;
const newPrices = await api.getAllCommodities();
// Check for price changes
const updated = [];
Object.keys(newPrices).forEach(commodity => {
if (prices.value[commodity] &&
prices.value[commodity].price !== newPrices[commodity].price) {
updated.push(commodity);
}
});
prices.value = newPrices;
lastUpdated.value = new Date();
recentlyUpdated.value = updated;
// Clear update indicators after 3 seconds
setTimeout(() => {
recentlyUpdated.value = [];
}, 3000);
} catch (err) {
error.value = err.message;
} finally {
loading.value = false;
}
};
const formatPrice = (price) => {
return typeof price === 'number' ? price.toFixed(2) : price;
};
const formatCommodityName = (commodity) => {
return commodity.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
};
const formatTime = (timestamp) => {
return new Date(timestamp).toLocaleString();
};
onMounted(() => {
fetchPrices();
// Update every 5 minutes
updateInterval = setInterval(fetchPrices, 5 * 60 * 1000);
});
onUnmounted(() => {
if (updateInterval) {
clearInterval(updateInterval);
}
});
return {
prices,
loading,
error,
lastUpdated,
recentlyUpdated,
fetchPrices,
formatPrice,
formatCommodityName,
formatTime
};
}
};
</script>
<style scoped>
.oil-prices-dashboard {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.header h1 {
font-size: 2.5rem;
color: #333;
margin-bottom: 10px;
}
.last-updated {
color: #666;
font-size: 0.9rem;
}
.loading {
text-align: center;
padding: 50px;
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.error {
text-align: center;
padding: 30px;
color: #e74c3c;
}
.retry-btn {
background: #3498db;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
margin-top: 10px;
}
.prices-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}
.price-card {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
text-align: center;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: all 0.3s ease;
}
.price-card.price-updated {
border-color: #2ecc71;
box-shadow: 0 0 10px rgba(46, 204, 113, 0.3);
animation: pulse 1s ease-in-out;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.price-card h3 {
margin: 0 0 15px 0;
color: #333;
font-size: 1.2rem;
}
.price {
font-size: 2rem;
font-weight: bold;
color: #2c3e50;
margin-bottom: 5px;
}
.unit {
color: #7f8c8d;
margin-bottom: 10px;
}
.timestamp {
font-size: 0.8rem;
color: #95a5a6;
}
</style>
Available Commodities
Brent Crude Oil
North Sea Brent crude oil, the global benchmark for oil pricing representing ~60% of internationally traded crude oil.
WTI Crude Oil
West Texas Intermediate crude oil, the primary benchmark for North American oil markets and NYMEX futures.
Dubai Crude Oil
Dubai crude oil benchmark for Middle Eastern crude oil pricing and Asian markets.
Natural Gas
NYMEX Henry Hub natural gas futures, the primary pricing benchmark for North American natural gas markets.
Natural Gas (UK)
UK natural gas pricing in British pence per therm.
Dutch TTF Gas
Dutch Title Transfer Facility (TTF) natural gas futures, the European gas pricing benchmark.
Gasoline RBOB
Reformulated Blendstock for Oxygenate Blending (RBOB) gasoline futures.
Heating Oil
No. 2 heating oil futures, a key refined petroleum product for heating and industrial use.
Coal
Coal futures pricing for thermal coal used in power generation.
Gold
Gold futures pricing, a key precious metal and safe-haven asset.
EUR/USD
Euro to US Dollar exchange rate, the most traded currency pair globally.
GBP/USD
British Pound to US Dollar exchange rate, also known as "Cable".
Best Practices
Error Handling
- Always use try/catch with async/await
- Check response.ok before parsing JSON
- Implement fallback data for offline scenarios
Performance
- Cache responses in localStorage/memory
- Use Promise.all() for parallel requests
- Implement request debouncing
Ready to Start Building?
Get your free API key and start integrating real-time commodity prices into your JavaScript applications today.