# Fuel Prices API: Cheapest Petrol & Diesel in France & Spain (`subtleasianmerch/fuel-prices`) Actor

Fuel prices for every filling station in France and Spain: petrol, diesel, E10 and LPG, cheapest first. From the governments' open data. Filter by city, postal code or radius, and schedule it to get only price changes.

- **URL**: https://apify.com/subtleasianmerch/fuel-prices.md
- **Developed by:** [Public Data Tools](https://apify.com/subtleasianmerch) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.40 / 1,000 stations

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Fuel Prices API: Cheapest Petrol & Diesel in France & Spain

Get the current **fuel prices** of every filling station in **France** and **Spain**, cheapest first, from the governments' own open data. Drivers, fleets and apps get petrol, diesel, E10 and LPG prices for their area in one format.

- ⛽ **About 21,000 stations:** about 9,800 in France and 11,400 in Spain.
- 🏛️ **Official open data, no web scraping:** France's prix-carburants.gouv.fr and Spain's Geoportal Gasolineras.
- 🏆 **Cheapest first:** sort by your fuel and keep the cheapest 10, 20 or 100.
- 📍 **Your area only:** a city, a postal code, or a point and a radius in km.
- 🔔 **Price-change alerts:** scheduled runs return only new stations and changed prices, with the old price.
- 💸 **$0.50 per 1,000 stations.** Stations outside your filters, and unchanged ones, are free.

**Try it:** the input comes pre-filled with an example. Click **Start** to get the 10 cheapest diesel stations in Paris and in Madrid, with their E10 and unleaded 95 prices. Then add your own cities.

### What you get

One row per station, in the same format for both countries:

| Data | What's in it |
|---|---|
| **Station** | address, postal code, city, region (French département or Spanish province), latitude and longitude; the brand in Spain |
| **Prices** | each fuel you chose: price in euros, per litre or kg, and when it was last updated |
| **Spreadsheet view** | `pricesByFuel`, the same prices as one object: `{ "diesel": 1.749, "e10": 1.689 }` |
| **Distance** | km from your point, when you give one |
| **Extras** | France: fuels out of stock, opening hours, services, motorway stations. Spain: opening hours |
| **Changes** | with a monitor ID: new stations, and each price's previous value, change and change in % |
| **Credit** | the data's date, the licence and the credit line the licence asks for |

**The sources:**

| Country | Source | Stations | Refreshed | Fuels |
|---|---|---|---|---|
| France | Prix des carburants, Ministry of the Economy (prix-carburants.gouv.fr) | about 9,800 | every 10 minutes | Diesel, E10, unleaded 95, super 98, E85, LPG |
| Spain | Geoportal Gasolineras, Ministry for the Ecological Transition | about 11,400 | every 30 minutes | Diesel, premium diesel, unleaded 95 and 98 (E5 and E10), LPG, CNG, LNG, AdBlue, hydrogen, renewable diesel and more |

### Who it's for

- **Drivers, fleets and logistics teams:** find the cheapest diesel around a depot or along a route, and track it daily.
- **Fuel-card, navigation and car apps:** add station prices for France and Spain through the Apify API, in one format.
- **Analysts, journalists and researchers:** follow fuel prices by city, region or brand, with history from scheduled runs.
- **Station operators and retailers:** watch competitors' prices around your stations and get told when they change.

### How much does it cost?

You pay **$0.50 per 1,000 stations** delivered ($0.0005 each), plus Apify's standard run start fee.

| Example | Stations | Cost |
|---|---|---|
| The pre-filled example: the 10 cheapest in Paris and in Madrid | 20 | $0.01 |
| Any 1,000 stations | 1,000 | $0.50 |
| Every French station with a price (a test run on 2 November 2026) | 9,074 | about $4.54 |

**Free:**

- stations outside your cities, postal codes or radius;
- stations selling none of your chosen fuels;
- stations beyond your "most stations per country" limit;
- with a monitor ID, stations whose prices haven't changed;
- countries whose source was blocked or failed.

Set a maximum cost per run in the run options. The run stops cleanly at that amount.

### How to use it

1. **Choose countries and your area:** France, Spain or both. Add cities (`Paris`, `A Coruña`), postal codes (`75015`, or `75` for all of Paris), or a point and a radius in km.
2. **Pick your fuels and the order:** for example Diesel and Unleaded 95 E10, cheapest first. Optionally keep only the cheapest 20 per country.
3. **For price alerts,** add a **Monitor ID** and schedule the Actor, for example hourly. Keep **Output only new stations and price changes** on.
4. **Click Start.** The **Stations** table shows the address, brand, prices, distance and data date. Export it as JSON, CSV or Excel.

Leave fuels empty to get every fuel. A city also matches its districts: "Paris" includes "PARIS 13". With both cities and a point, a station is kept when it matches either.

### Example input

**The 20 cheapest E10 stations within 10 km of central Lyon:**

```json
{
  "countries": ["FR"],
  "latitude": 45.764,
  "longitude": 4.8357,
  "radiusKm": 10,
  "fuels": ["e10"],
  "maxStationsPerCountry": 20
}
```

**Diesel and AdBlue in three Spanish cities, cheapest diesel first:**

```json
{
  "countries": ["ES"],
  "locations": ["Zaragoza", "Huesca", "Lleida"],
  "fuels": ["diesel", "adblue"]
}
```

**Daily price alerts for all of Paris (schedule it once a day):**

```json
{
  "countries": ["FR"],
  "locations": ["75"],
  "fuels": ["diesel", "e10", "petrol_98"],
  "monitorId": "paris-daily"
}
```

### Example output

One row per station. This is a real record from the Spanish data of 31 October 2026, shortened to two fuels:

```json
{
  "country": "ES",
  "countryName": "Spain",
  "source": "Geoportal Gasolineras (MITECO)",
  "stationId": "16166",
  "brand": "CEPSA",
  "name": null,
  "address": "AVENIDA JUAN DE BORBON, 27",
  "postalCode": "51001",
  "city": "Ceuta",
  "region": "CEUTA",
  "latitude": 35.894167,
  "longitude": -5.324056,
  "distanceKm": null,
  "matchedLocations": ["Ceuta"],
  "prices": [
    { "fuel": "diesel", "fuelName": "Gasoleo A", "price": 1.749, "currency": "EUR", "unit": "litre", "updatedAt": "2026-10-31T08:40:30+01:00", "previousPrice": null, "change": null, "changePercent": null },
    { "fuel": "petrol_95", "fuelName": "Gasolina 95 E5", "price": 1.594, "currency": "EUR", "unit": "litre", "updatedAt": "2026-10-31T08:40:30+01:00", "previousPrice": null, "change": null, "changePercent": null }
  ],
  "pricesByFuel": { "diesel": 1.749, "petrol_95": 1.594 },
  "outOfStock": [],
  "openingHours": "L-D: 24H",
  "services": [],
  "details": { "locality": "CEUTA", "municipalityId": "8110", "provinceId": "51", "autonomousCommunityId": "18", "saleType": "public", "bioethanolPercent": 0, "methylEsterPercent": 0 },
  "isNew": null,
  "previousSeenAt": null,
  "dataUpdatedAt": "2026-10-31T08:40:30+01:00",
  "sourceUrl": "https://sedeaplicaciones.minetur.gob.es/ServiciosRESTCarburantes/PreciosCarburantes/EstacionesTerrestres/FiltroProvincia/51",
  "licence": "Spanish public-sector reuse conditions (Ley 37/2007): free reuse, citing the source and update date",
  "licenceUrl": "https://sede.serviciosmin.gob.es/es-ES/Paginas/aviso.aspx",
  "attribution": "Origen de los datos: Ministerio para la Transición Ecológica y el Reto Demográfico, Geoportal Gasolineras (servicio REST del Ministerio de Industria y Turismo); precios en vigor a 2026-10-31T08:40:30+01:00",
  "fetchedAt": "2026-10-31T08:01:16.229Z"
}
```

With a monitor ID, a station whose diesel went up looks like this in `prices` (values from a test):

```json
{ "fuel": "diesel", "fuelName": "Gasoleo A", "price": 1.799, "previousPrice": 1.749, "change": 0.05, "changePercent": 2.86 }
```

#### About the fields

- **Fuel types** (`fuel`): `diesel`, `e10`, `petrol_95` (E5), `petrol_98`, `diesel_premium`, `petrol_95_premium`, `petrol_98_e10`, `e85`, `lpg`, `cng`, `lng`, `adblue`, `hydrogen`, `diesel_renewable` (HVO), `petrol_renewable`, `diesel_offroad` (Spain's gasóleo B), `biodiesel`, `bioethanol`, `biocng`, `biolng`, `methanol`, `ammonia`. A fuel with no normalised type is `other`, with its own name in `fuelName`.
- `price`: in euros, per `unit`. Gases (CNG, LNG, hydrogen) are per kg; liquids, LPG and AdBlue per litre.
- `updatedAt`: France gives each price's own update time. Spain gives the time of its data file, refreshed every 30 minutes.
- `city`: France gives the town as each station wrote it (`PARIS`, `Paris` or `PARIS 13`); Spain gives the municipality, with the locality in `details`.
- `region`: France's département, worked out from the postal code; Spain's province as the source writes it.
- `outOfStock` (France): fuels the station has reported as temporarily unavailable, with the date. A station that has stopped selling a fuel for good doesn't list it.
- `openingHours`: France gives the counter's hours, e.g. `Mon-Sat 07:00-19:30; Sun closed`. The pumps may still take cards 24/7: see `details.automate24h`. Spain gives its own text, e.g. `L-D: 06:00-22:00`, with Spanish day letters: L = Monday, M = Tuesday, X = Wednesday, J = Thursday, V = Friday, S = Saturday, D = Sunday.
- `isNew`, `previousSeenAt`, `previousPrice`, `change`, `changePercent`: filled in with a monitor ID, `null` without one.

**Run summary:** the log shows each country's count and its cheapest station for your first fuel. The `RUN_SUMMARY` record in the run's key-value store lists, per country:

- the source's status (`ok`, `blocked`, `busy`, `format changed` or `failed`) and the reason;
- what was downloaded, and the data's date;
- stations read, matching your area, without your fuels, beyond your limit, unchanged and delivered;
- the cheapest station for each fuel in your area.

It also lists how many stations matched each of your locations.

### Integrations

- **Schedules:** run it hourly or daily in Apify Console. With a monitor ID, each run returns only price changes.
- **Apify API:** start a run and get the stations back as JSON in one call:

  ```bash
  curl -X POST "https://api.apify.com/v2/acts/subtleasianmerch~fuel-prices/run-sync-get-dataset-items?token=YOUR_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"countries": ["FR"], "locations": ["Lyon"], "fuels": ["diesel"], "maxStationsPerCountry": 5}'
  ```

  Replace `YOUR_TOKEN` with your Apify API token.
- **Webhooks:** call your own endpoint when a run finishes, for example to push price changes into your app.
- **Make, Zapier and n8n:** send new prices to Slack, email or a database with Apify's apps for these tools.
- **Monitoring:** Apify's monitoring can alert you when a scheduled run fails or returns fewer results than usual.

### FAQ

#### Is it legal to use?

Both sources publish this data as open data. Their reuse terms, read on 31 October 2026, allow commercial reuse with credit:

- **France:** the Licence Ouverte 2.0 asks you to name the source and the date of the last update.
- **Spain:** the public-sector reuse rules (Ley 37/2007) ask you to cite the source and the update date, and not to change the data's meaning.

Every row carries a ready-made `attribution` line with the date; keep it when you publish the data. The rows describe businesses, not people. This isn't legal advice: check the licences against your own use.

#### Do I need any accounts or keys?

No. Both sources are open.

#### How fresh are the prices?

French prices come from a file the ministry refreshes every 10 minutes; Spanish prices from data refreshed every 30 minutes. Each run reads them live. `dataUpdatedAt` shows when the source produced its data.

#### Are the prices always right?

They are as reported. Stations report their own prices to the ministries, and a few may be out of date. Check `updatedAt`.

#### Why is the brand empty for French stations?

The French government's open data deliberately leaves out station names and brands. The address, postal code and position identify each station. Spain gives each station's sign, usually the brand.

#### Why didn't my Spanish town match?

Spanish names are matched against the official list of municipalities, for example "Madrid", "A Coruña", "Alicante" or "Alacant". A smaller place inside a municipality won't match by name: use its postal code, or a point with a radius.

#### How do I track prices over time?

Give the run a monitor ID and schedule it, for example every hour. With "Output only new stations and price changes" off, every run outputs every station, with changes marked, for a full history.

#### How does it read the data?

Politely. France publishes one file for the whole country (about 1.2 MB), downloaded once per run. Spain's service is read only for the municipalities or provinces you need, or as one full list (12 MB) for the whole country. Requests are paced, and the Actor says it's a bot.

#### What if a source is down or blocks the Actor?

If a source asks it to slow down, it waits and retries. If a source blocks it, that country stops, the other continues, and the run summary says so. If a source changes its format, the run fails loudly after delivering the other country, so you never get silently wrong prices.

#### Can I get other countries?

Not yet. Italy's official files couldn't be reached from Apify's servers when this Actor was built. Germany's data comes with terms that rule out this use, and Austria publishes prices only for the few cheapest stations near a point. The UK's Fuel Finder needs a registered account. Ask on the Issues tab if you need another country.

### Related Actors

More Actors from the same developer that work well with this one:

| Actor | Use it to |
|---|---|
| [Australian Supermarket Prices](https://apify.com/subtleasianmerch/australian-grocery-prices) | track grocery prices at Woolworths and Aldi Australia, with the same price-change monitoring |

Questions, bugs or ideas? Open an issue on this Actor's **Issues** tab.

# Actor input Schema

## `countries` (type: `array`):

Whose official open data to read. France: about 9,800 stations, refreshed every 10 minutes. Spain: about 11,400 stations, refreshed every 30 minutes.

## `locations` (type: `array`):

One per line, e.g. Paris, Lyon, Madrid, A Coruña, 75015 or 28031. A shorter postal code covers an area: 75 is all of Paris, 28 all of Madrid province. City districts count too ("Paris" includes "PARIS 13"). Leave empty, with no point below, for every station in the chosen countries.

## `latitude` (type: `number`):

With longitude and radius: stations within the radius of this point, e.g. 48.8566 for central Paris. Combined with the cities above, a station is kept when it matches either.

## `longitude` (type: `number`):

E.g. 2.3522 for central Paris.

## `radiusKm` (type: `number`):

Used only with a latitude and longitude. Each station gets its distance from the point (distanceKm).

## `fuels` (type: `array`):

Only these fuels' prices are output, and stations selling none of them are left out, free. Leave empty for every fuel. Each price also keeps the source's own fuel name (e.g. Gazole, Gasoleo A).

## `sortBy` (type: `string`):

Cheapest first (by the first fuel type you chose, or diesel if none), nearest first (needs a point), or as the source lists them. With a limit below, the order decides which stations are kept.

## `maxStationsPerCountry` (type: `integer`):

E.g. 20 for the 20 cheapest stations in each country's matching area. Leave empty for every matching station. Each station delivered is charged.

## `monitorId` (type: `string`):

Any name, e.g. "paris-diesel". Runs with the same ID remember each station's last prices, so a schedule can report new stations and price changes, with the old price, the change and the percentage.

## `onlyChanges` (type: `boolean`):

With a monitor ID: on, only stations that are new or whose price for a chosen fuel changed since the last run (unchanged stations are free); off, every station, with changes marked.

## Actor input object example

```json
{
  "countries": [
    "FR",
    "ES"
  ],
  "locations": [
    "Paris",
    "Madrid"
  ],
  "radiusKm": 10,
  "fuels": [
    "diesel",
    "e10",
    "petrol_95"
  ],
  "sortBy": "cheapest",
  "maxStationsPerCountry": 10,
  "onlyChanges": true
}
```

# Actor output Schema

## `results` (type: `string`):

The dataset rows this run produced.

## `runSummary` (type: `string`):

Counts, costs and anything skipped, saved as RUN_SUMMARY.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "countries": [
        "FR",
        "ES"
    ],
    "locations": [
        "Paris",
        "Madrid"
    ],
    "fuels": [
        "diesel",
        "e10",
        "petrol_95"
    ],
    "maxStationsPerCountry": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("subtleasianmerch/fuel-prices").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "countries": [
        "FR",
        "ES",
    ],
    "locations": [
        "Paris",
        "Madrid",
    ],
    "fuels": [
        "diesel",
        "e10",
        "petrol_95",
    ],
    "maxStationsPerCountry": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("subtleasianmerch/fuel-prices").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "countries": [
    "FR",
    "ES"
  ],
  "locations": [
    "Paris",
    "Madrid"
  ],
  "fuels": [
    "diesel",
    "e10",
    "petrol_95"
  ],
  "maxStationsPerCountry": 10
}' |
apify call subtleasianmerch/fuel-prices --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,subtleasianmerch/fuel-prices"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/6tIrphfVfQ8Ug9MRp/builds/9iy9WErw9taU0AgxA/openapi.json
