# Europe Official Fuel Prices (FR, ES) (`homelabmobile/eu-fuel-prices`) Actor

Official pump prices from the French and Spanish government open-data feeds: one row per station and fuel, with brand, address, coordinates, price and update time.

- **URL**: https://apify.com/homelabmobile/eu-fuel-prices.md
- **Developed by:** [Home Lab Mobile](https://apify.com/homelabmobile) (community)
- **Categories:** Travel, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Europe Official Fuel Prices (FR, ES)

Get current pump prices from the official government open-data feeds of **France and Spain** as
clean JSON. You get one row per station and fuel type, with brand, address, coordinates, the price and when it
was last updated. The data comes straight from the ministries' public open-data files, so no login, API key
or scraping of commercial sites is involved.

### What it does

- Covers about 21,000 stations: France (prix-carburants, about 9,800) and Spain (MITECO Geoportal Gasolineras, about 11,500). Italy is temporarily unavailable (see Known limits).
- Puts both countries into one schema. Each row has a normalised `fuelType` (`diesel`, `petrol_95`, `petrol_95_e10`, `petrol_98`, `lpg`, `cng`, ...) for comparing across countries, and the source's own `fuelName`.
- Filters by country, fuel type, municipality, province/departement or postcode prefix.
- Carries the attribution on every row (`source`, `sourceUrl`, `license`, `sourceUpdatedAt`), so you can meet each licence's terms when you reuse the data.
- Returns one result per station and fuel. You pay only for valid results; malformed rows are dropped and not charged.
- Fails loudly: if a source returns nothing usable or changes its format, the run fails instead of
  returning an empty or broken dataset. A run that finds no station matching your filters ends
  successfully with zero results and no charge.

### Input

| Field | Type | Required | Description |
|---|---|---|---|
| `countries` | array of `FR`, `ES` | no | Countries to include, in output order. Default: both. |
| `fuelTypes` | array | no | Normalised fuel types to keep, e.g. `["diesel", "petrol_95"]`. Default: all. |
| `municipality` | string | no | Town or city, whole-name match ignoring case and accents, e.g. `Lyon`, `Madrid`. |
| `province` | string | no | FR departement (`75`, `2A`), ES province name or INE code (`Madrid`, `28`). |
| `postcodePrefix` | string | no | Postcode prefix, e.g. `750` (central Paris) or `28` (Madrid province). |
| `maxResults` | integer | no | Stop after this many rows (default 100, max 200,000). Caps the cost of a run. |

Examples:

```json
{ "countries": ["FR"], "postcodePrefix": "750", "maxResults": 50 }
```

```json
{ "countries": ["FR"], "province": "69", "fuelTypes": ["diesel", "petrol_95_e10"], "maxResults": 100 }
```

```json
{ "countries": ["ES"], "province": "Madrid", "maxResults": 1000 }
```

#### Calling from an AI agent (MCP)

This Actor works as a tool through the [Apify MCP server](https://mcp.apify.com). Example tool call:

```json
{ "actor": "homelabmobile/eu-fuel-prices", "input": { "countries": ["ES"], "municipality": "Valencia", "fuelTypes": ["diesel"], "maxResults": 20 } }
```

### Output

One JSON object per station and fuel. This is a real row from a local run on 2026-10-14:

```json
{
    "country": "ES",
    "stationId": "15493",
    "stationName": null,
    "brand": "PLENERGY",
    "address": "CAMINO TORREJON, 4",
    "municipality": "Ajalvir",
    "province": "MADRID",
    "postcode": "28864",
    "latitude": 40.528778,
    "longitude": -3.481639,
    "onMotorway": null,
    "openingHours": "L-D: 24H",
    "fuelType": "diesel",
    "fuelName": "Gasoleo A",
    "selfService": null,
    "price": 1.809,
    "currency": "EUR",
    "priceUnit": "EUR/l",
    "priceUpdatedAt": null,
    "sourceUpdatedAt": "2026-10-14T02:44:35.000Z",
    "source": "Ministerio para la Transición Ecológica / Ministerio de Industria y Turismo - Precios de carburantes (Geoportal Gasolineras)",
    "sourceUrl": "https://geoportalgasolineras.es/",
    "license": "Reutilización según Ley 37/2007 (cite la fuente y la fecha de actualización)",
    "scrapedAt": "2026-10-14T02:45:06.507Z"
}
```

Field notes:

- `selfService` and `stationName` are always null for France and Spain, whose feeds do not publish them. They are kept in the schema for Italy, which publishes both, for when it returns.
- `priceUpdatedAt` is when the station last reported that price (France only; null for Spain). `sourceUpdatedAt` is the dataset's own update time (both countries).
- `brand`: France's open feed has no brand, so it is null there.
- `priceUnit` is `EUR/kg` for CNG, LNG, biogas and hydrogen, and `EUR/l` for everything else.

Each run also writes a `RUN_SUMMARY` record (status, counts) to its key-value store. If a country's official source is down, the run still returns the other countries' results, says so in the status message and writes a `SOURCE_ERRORS` record (country, error, rows pushed before the failure).

### Sources, licences and attribution

If you reuse the data, keep the attribution below. Every row carries its `source`, `sourceUrl`, `license` and `sourceUpdatedAt`.

| Country | Publisher and dataset | Licence | Update frequency |
|---|---|---|---|
| France | Ministère de l'Économie et des Finances, "Prix des carburants en France - Flux instantané" ([data.gouv.fr](https://www.data.gouv.fr/datasets/prix-des-carburants-en-france-flux-instantane-v2-amelioree), file from donnees.roulez-eco.fr) | [Licence Ouverte v2.0 (Etalab)](https://www.etalab.gouv.fr/licence-ouverte-open-licence/) (attribution required) | Every 10 minutes |
| Spain | Ministerio para la Transición Ecológica y el Reto Demográfico / Ministerio de Industria y Turismo, Geoportal Gasolineras, REST service "PreciosCarburantes/EstacionesTerrestres" ([Geoportal](https://geoportalgasolineras.es/)) | Reuse under Ley 37/2007 (art. 8 general conditions, [aviso legal](https://sede.serviciosmin.gob.es/es-ES/Paginas/aviso.aspx)): do not alter or misrepresent the data, cite the source, and state the date of the last update | Every 30 minutes |

Attribution text you can use:

- "Source: Ministère de l'Économie et des Finances - Prix des carburants (flux instantané), Licence Ouverte v2.0, updated `sourceUpdatedAt`."
- "Fuente: Ministerio para la Transición Ecológica y el Reto Demográfico / Ministerio de Industria y Turismo - Geoportal Gasolineras. Fecha de última actualización: `sourceUpdatedAt`."

For Spain this Actor changes only the format: decimal commas become numbers, dates become ISO 8601 UTC, and a normalised `fuelType` is added. Names, addresses and prices are not changed, and the original product name stays in `fuelName`.

### Pricing

Pay per event:

| Event | Price | Per 1,000 |
|---|---|---|
| Result (one valid station x fuel row) | $0.001 | $1.00 |

Plus Apify's standard Actor start charge. A typical run of 50 rows costs about $0.05. A full snapshot of
both countries is about 77,000 rows (about $77), so use filters and `maxResults` unless you
really need everything.

### Known limits

- Countries: France and Spain only.
  - Italy is temporarily unavailable: the MIMIT open-data server was unreachable from Apify for days in October 2026. We check it weekly and will add Italy back once it is reliably reachable. Until then the input does not accept `IT`, and Apify rejects such an input before the run starts, so nothing is charged.
  - Austria (E-Control Spritpreisrechner) is not included until its reuse terms are confirmed.
  - Portugal is excluded because the DGEG terms forbid commercial use.
  - The UK is excluded because its statutory feed needs a GOV.UK One Login account.
- France and Spain are near real time (updated every 10 and 30 minutes).
- French rows have no brand or station name. Spain has no per-price timestamp.
- Each run downloads the national file for every selected country: a 1 MB ZIP for France and 12 MB of JSON for Spain. Filters are applied after the download, so a small filtered run still takes a few seconds per country.
- Rows come out country by country, in source order. With a small `maxResults` and several countries, you may only get rows from the first country.
- A municipality filter must match the whole name as the source spells it (case and accents are ignored). For example, Spain uses `Palmas de Gran Canaria (Las)`.
- If one country's government server is down, that country is skipped and listed in `SOURCE_ERRORS`; you are only charged for rows you get. The run fails only if every country you asked for fails, or if no rows come back. Each source gets at most 4 attempts, a few seconds apart.
- Public open data only. It does not log in or bypass any access control. It makes at most 2 requests per run, one at a time.

### Support

Open an issue on the Actor's Issues tab. We reply within 2 business days.

# Actor input Schema

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

ISO country codes to include, in this order: "FR" (France, about 9,800 stations, updated every 10 minutes), "ES" (Spain, about 11,500 stations, updated every 30 minutes). Leave empty for both. Italy is temporarily unavailable because its official server is unreachable. Rows come out country by country, so put the country you care most about first when maxResults is small.

## `fuelTypes` (type: `array`):

Optional. Only return these normalised fuel types. petrol_95 = unleaded 95 (E5, French SP95), petrol_95_e10 = E10, petrol_98 = unleaded 98, petrol_premium = branded premium petrol, e85 = bioethanol E85, diesel = standard diesel (French Gazole, Spanish Gasoleo A), diesel_premium = branded premium diesel, diesel_agricultural = Spanish Gasoleo B, hvo = HVO/renewable diesel, lpg = LPG/autogas, cng = compressed natural gas/methane, lng = liquefied natural gas, hydrogen, adblue, other = anything else. Leave empty for all fuels.

## `municipality` (type: `string`):

Optional. Only stations in this municipality (town or city), matched on the whole name, ignoring case and accents, e.g. "Lyon", "Madrid". For Spain the station's 'Localidad' is also matched.

## `province` (type: `string`):

Optional. Only stations in this province. France: departement number, e.g. "75", "69", "2A". Spain: province name or two-digit INE code, e.g. "Madrid" or "28". Case and accents are ignored.

## `postcodePrefix` (type: `string`):

Optional. Only stations whose postcode starts with this, e.g. "750" for central Paris or "28" for Madrid province.

## `maxResults` (type: `integer`):

Stop after this many rows (one row = one station and fuel type). You are charged per row, so this caps the cost of a run. A full snapshot of both countries is about 77,000 rows.

## Actor input object example

```json
{
  "countries": [
    "FR"
  ],
  "maxResults": 50
}
```

# Actor output Schema

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

One JSON object per result; fields are described in the dataset schema.

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

RUN_SUMMARY: status, counts and the silent-failure verdict for this run.

## `sourceErrors` (type: `string`):

SOURCE_ERRORS: written only when a country's official source failed (outage, timeout). Lists the country, error and rows pushed before the failure; the other countries' results are still in the dataset.

# 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"
    ],
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("homelabmobile/eu-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"],
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("homelabmobile/eu-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"
  ],
  "maxResults": 50
}' |
apify call homelabmobile/eu-fuel-prices --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,homelabmobile/eu-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/hOuXFlqlDVdclCzHs/builds/4gTWzaT8bsI3LSFrT/openapi.json
