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 axiosnpm install node-cache # for Node.js cachingnpm install express cors # for Node.js server2. 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.
JKM LNG
Japan/Korea Marker (JKM) LNG futures, the primary pricing benchmark for Asian liquefied natural gas markets.
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".
VLSFO Marine Fuel
Very Low Sulfur Fuel Oil, IMO 2020 compliant marine fuel for commercial shipping.
Marine Gas Oil 0.5%S
Marine Gas Oil with 0.5% sulfur content, compliant with IMO 2020 emission standards.
Heavy Fuel Oil 380
Heavy Fuel Oil with 380 cSt viscosity, traditional marine bunker fuel for large vessels.
Heavy Fuel Oil 180
Heavy Fuel Oil with 180 cSt viscosity, medium-grade marine bunker fuel for shipping.
Tapis Crude Oil
Malaysian Tapis Crude Oil - Light Sweet Asian benchmark oil used for pricing in Southeast Asia.
Western Canadian Select
Western Canadian Select heavy crude oil, the primary Canadian oil benchmark.
Urals Crude Oil
Russian Urals crude oil, the primary Russian export grade and Eastern European benchmark.
Diesel (Gulf Coast)
U.S. Gulf Coast Ultra-Low Sulfur No 2 Diesel spot price, critical for transportation and logistics.
ULSD Diesel (NY Harbor)
Ultra Low Sulfur No 2 Diesel spot price FOB New York Harbor, the NYMEX delivery standard.
Jet Fuel
Kerosene-type jet fuel spot price, essential for aviation industry fuel costs and planning.
Ethanol
Ethanol fuel pricing, renewable biofuel component for gasoline blending.
EU Carbon Allowances
European Union Emissions Trading System (EU ETS) carbon allowance pricing.
International Rig Count
Monthly active drilling rig count for international markets outside North America, sourced from Baker Hughes.
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.