GasBuddy Scraper: Fuel Prices, Stations & Reviews avatar

GasBuddy Scraper: Fuel Prices, Stations & Reviews

Pricing

from $1.00 / 1,000 station results

Go to Apify Store
GasBuddy Scraper: Fuel Prices, Stations & Reviews

GasBuddy Scraper: Fuel Prices, Stations & Reviews

Scrape GasBuddy station by station across the US and Canada. Returns brand, address, coordinates, phone, amenities, open status, ratings and reviews, plus the current cash and credit price for every fuel grade with who reported it and when. Incremental mode tracks price changes between runs.

Pricing

from $1.00 / 1,000 station results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

5

Total users

0

Monthly active users

2 days ago

Last modified

Categories

Features

Limited permissions

Share

GasBuddy Scraper: Station Fuel Prices, Amenities & Reviews

GasBuddy Station and Fuel Price Scraper turns GasBuddy into station level fuel price data for the United States and Canada. For every station it returns the brand, the full postal address, coordinates, phone, amenities, opening status, member rating and reviews, and the current cash and credit price for every fuel grade the station sells, together with when that price was reported and which member reported it. Search by postal code, city, state or a coordinate radius, or paste station and search links directly, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.

Why This Scraper?

  • Station level pricing, not a state average. Every fuel grade a station sells comes back with its own cash price, credit price, formatted price, member discount, and who reported it and when.
  • Two ways to search. Look up a postal code, a city and state, a state wide sweep, or a coordinate pair for a radius search, or paste station and search links directly.
  • Filters beyond the site's own. Brand (checked against GasBuddy's own brand list), fuel grade and price age narrow the search itself; price range, star rating, amenities, open now and has a reported price are applied on top of the results, including amenity filtering GasBuddy does not offer.
  • Reviews on demand, priced fairly. The first page of member reviews for every station arrives free with the search itself. Only asking for more rows than that page holds triggers an extra, clearly priced request.
  • Built for price monitoring. Incremental mode returns only the stations whose price (or anything else) actually moved on a scheduled run, with changedFields naming exactly what changed, turning a live snapshot into a price history over time. GasBuddy does not publish a per-station price time series, so every row is the current snapshot; schedule runs in incremental mode to build your own history.
  • Resume an interrupted crawl, or split a very large sweep across several runs with a page position on a pasted search link, without re-reading or re-paying for rows a previous run already returned.
  • Fails loudly instead of lying. If the site refuses every request, the run stops with a clear message so "no stations here" is never confused with "the read was blocked".

Use Cases

  • Fuel price comparison apps: pull the cheapest current price per grade across an area to power a station finder or a price alert tool.
  • Market and competitor pricing research: track brand level and area pricing over time with Incremental mode, without re-paying for stations whose price has not moved.
  • Fleet and logistics fuel planning: filter by grade, price range and amenities such as diesel or truck stop access along a route.
  • Site selection and local research: amenities, opening status and member ratings for a station or a whole area.
  • Data journalism and price trend research: build a dataset of regional price movement using scheduled Incremental runs and changedFields.

Data You Get

Sample shape: values are illustrative placeholders, not from a live record.

FieldExample
stationId"90210001"
name"Example Fuel Stop"
urlGasBuddy link to the station
brand / brandId"Example Fuel Brand" / "501"
addressLine1 / city / state / postalCode / country"400 Sample Ave" / "Example City" / "TX" / "00000" / "US"
latitude / longitude29.9012 / -95.4123
phone"555-010-0100"
distance / distanceMiles"1.2mi" / 1.2 (coordinate searches only)
openStatus"open"
amenities["C-Store", "Pay At Pump", "Air Pump"]
fuels["regular_gas", "midgrade_gas", "premium_gas", "diesel"]
pricesone row per grade: cash price, credit price, formatted price, member discount, reported at, reported by
lowestPrice / lowestPriceFuelType3.29 / "regular"
lastPriceReportedAt / lastPriceReportedBy"2026-02-01T09:00:00.000Z" / "sample-member"
priceUnit / currency"dollars_per_gallon" / "USD"
starRating / ratingsCount4.1 / 56
reviewCount / reviews12 / member reviews (when Include member reviews is on)
priceTrendthe area price context GasBuddy publishes beside the station: today's average, today's low, direction
cardPaymentAvailabletrue
hasActiveOutagefalse
changeType / changedFields"UPDATED" / ["lowestPrice", "prices"] (Incremental mode only)
firstSeenAt / lastSeenAttimestamps this actor tracked the station (Incremental mode only)

Every record also carries allBrands, addressLine2, openingHours, nextOpenAt, nextCloseAt, amenityIds, topSpotters (the crowd's top price spotters), offers (member discount offers), emergencyStatus, isTruckFleetSite, isEnterprise, searchTerm, searchLocation and scrapedAt.

How to Use

  1. Pick a mode: search (postal code, city, state or coordinate pair) or url (paste station or search links).
  2. Fill in Locations or the links you pasted, then narrow the results with the filters: brand, fuel grade, price age, price range, star rating, amenities, open now, or has a reported price.
  3. Set Max stations (and, if you need to, Max pages and Max reviews per station) to control run size and cost, then click Start.
  4. Download the dataset as JSON, CSV or Excel, or read it through the API.

Search a city with a brand and grade filter:

{
"mode": "search",
"locations": ["Example City, TX"],
"brands": ["Shell"],
"fuelType": "regular",
"maxStations": 20
}

Coordinate radius search, open stations only:

{
"mode": "search",
"locations": ["40.0,-75.0"],
"maxDistanceMiles": 5,
"openNowOnly": true
}

Paste station and search links:

{
"mode": "url",
"urls": [
"https://www.gasbuddy.com/station/29981",
"https://www.gasbuddy.com/home?search=00000"
]
}

Recurring price monitoring for the same search:

{
"mode": "search",
"locations": ["Example City, TX"],
"incrementalMode": true,
"maxStations": 0
}

URL mode with the links field left empty scrapes one example of each shape in the table below. Replace the list with your own links to scrape those instead. A link that is not recognised is named in the run log and skipped, never silently ignored.

ShapeExampleWhat you get
Station pagehttps://www.gasbuddy.com/station/29330That station, always returned even when the filters would exclude it.
Bare station id29330The same station.
Station page, host without www or mobile hosthttps://gasbuddy.com/station/29330, https://m.gasbuddy.com/station/29330The same station, read by its stable id.
Search by postal codehttps://www.gasbuddy.com/home?search=78701Stations around that postal code.
Search, later pagehttps://www.gasbuddy.com/home?search=Austin%2C%20TX&page=2The walk starts at that page.
Coordinate search with row offsethttps://www.gasbuddy.com/home?search=30.2672,-97.7431&fuel=1&cursor=50A radius search starting at row 50.
State or city price pagehttps://www.gasbuddy.com/gasprices/texas/austinRead as a search for that city and state.

A link that starts deeper with &page= or &cursor= covers only part of the area, so a recurring run never marks stations outside that slice as expired.

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/gasbuddy-com-scraper").call(run_input={
"mode": "search",
"locations": ["Example City, TX"],
"maxStations": 20,
})
for station in client.dataset(run["defaultDatasetId"]).iterate_items():
print(station["name"], station["lowestPrice"], station["lowestPriceFuelType"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/gasbuddy-com-scraper').call({
mode: 'search',
locations: ['Example City, TX'],
maxStations: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

How Max stations and Max pages shape a run

Max stations stops the whole run after that many matching stations, shared across every location in the run so each one contributes instead of the first location spending the whole budget. Max pages stops each individual location after that many result pages regardless of Max stations. 0 on either means no cap; on a whole state that can be thousands of billed rows, so start narrow and raise it once you know the size of the area. When locations overlap (for example a postal code and the city around it), a station one location read but left over once its share was full is not offered again by the next location, so such a run can return fewer than Max stations even though more matching stations exist; list areas that do not overlap, or raise Max stations.

Tip: with Incremental mode on, a small Max stations can under count a schedule. Max stations is shared out across your locations, and each location stops reading once it has gathered its share of matching stations. That share is counted before this actor knows which of those stations are actually new or changed (with no filter on, it even shrinks the page it asks the site for down to that share). If the stations it reads first turn out to be unchanged since the last run, they are correctly suppressed and not billed, but the location still stops there, even though Max stations was never reached. A genuinely new or changed station further down the same search is never read, the run can log "nothing changed since the last run", and because every scheduled run with the same input stops at the same place, that change can stay unseen run after run. This never creates false EXPIRED rows: a location stopped by its share is not treated as a complete scan, and a station that was read is never marked as disappeared. Workaround: for a scheduled Incremental campaign, set Max stations generously (comfortably above the number of stations you expect to track, or 0 for no limit) so the walk is never cut short before it reaches the whole tracked area.

Resume and recurring updates

  • Resume from a previous run (resumeFromRunId) continues one interrupted crawl: paste its run or dataset id and the stations it already returned are skipped, so you don't pay twice. It only bootstraps Incremental mode's saved state when that state is still empty (the first run for a search); pointed at a search that already has tracked history, the run fails with a clear message asking you to remove Resume or pick a different State key instead.
  • Incremental mode (incrementalMode) is for scheduled runs over the same search. It remembers the previous run itself, so no id has to be pasted anywhere. Each station is classified NEW, UPDATED (with changedFields naming what changed), UNCHANGED (suppressed and not billed unless Also return unchanged stations is on), REAPPEARED, or EXPIRED (only after a run that completed a full scan of the search, and only with Also return stations that disappeared on). stateKey names or shares the stored state; left empty, a key is derived from the mode, locations, links and every filter, so changing a filter starts a fresh baseline rather than silently mixing two searches.

Tip: EXPIRED rows never exceed the room left under Max stations. Also return stations that disappeared tombstones tracked stations that are no longer found, but only after a complete scan, and no more than Max stations minus the rows already returned in that run (with Max stations at 0 there is no limit). Stations beyond that stay tracked and are tombstoned by a later run, so a long gap or a lowered Max stations cannot bill one huge batch. With Expire after missed scans above 1, a station must be missing from that many complete scans in a row first; EXPIRED means the site stopped listing it in this search, not that it closed.

Tip: starting Incremental mode from Resume does not re-bill the resumed stations. When Resume bootstraps an empty Incremental state, the stations the earlier run already returned are saved by id only. On the next ordinary Incremental run each of them is recorded as UNCHANGED the first time it is seen again (and so not billed) and compared normally from then on. If one disappears before then it is skipped (and counted in the log) rather than emitted as an incomplete EXPIRED row. After an Apify platform migration that restarts an Incremental run midway, stations returned before the restart can come back once more on the next run.

priceTrend, offers, reviews and topSpotters never appear in changedFields. priceTrend is an area aggregate shared by every station in a metro and recomputed continuously, so tracking it would relabel a whole city as changed with no station level change behind it. offers carries a fresh opaque id on nearly every fetch for the same promotion. reviews and topSpotters are excluded on size, because a busy station's review corpus would not fit in the saved baseline. Nothing is lost: reviewCount, ratingsCount and starRating are all tracked, so a new review still shows up as an UPDATED station naming those fields.

Send results into your apps (MCP connectors)

Optionally pipe results into the apps you already use through Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed and nothing extra is charged.

  1. Authorize a connector once under Apify -> Settings -> Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the mcpConnectors field. (If the picker is empty, you have not authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where station entries should be created.

Each station becomes one entry with a title and its key fields as plain text; the complete record always stays in the Apify dataset. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch (locations) or url (paste station or search links). Links or Stations given with no location of any kind always run in url mode.
locationsarray(prefill 78701; search mode with no target of any kind searches 78701)One entry per area: postal code, city and state, state, or latitude,longitude for a radius search. Search mode only.
urlsarrayone example of each link shape (see below)Station, search or price-page links, or bare station ids. URL mode only.
brandsarray(none)Return only these brands, checked against GasBuddy's own brand list.
brandNamesarray(none)Alias of brands; both lists are merged.
zipCodesarray(none)Alias for postal codes in locations (search mode).
cityStatesarray(none)Alias for City, ST entries in locations (search mode).
coordinatesarray(none)Objects with latitude and longitude; each is a radius search (search mode).
stationsarray(none)Alias for station ids or links in urls, read in url mode only: with Locations also given and Mode left on search, the run stays in search mode, the Stations are not looked up, and the run log says so. If you set Mode to url explicitly, the Stations are looked up and the Locations are not read. A station the site does not return is listed in the LOOKUP_STATUS key-value record, never as a dataset row, so it is not billed.
streetAddressesarray(none)Full street addresses; used alone, only stations whose street line matches are kept (search mode).
fuelTypestringregularThe grade GasBuddy ranks the area by; every grade a station sells is still returned.
maxPriceAgeHoursstring0 (any age)Keep only stations whose price was confirmed within this many hours.
maxReportAgeHoursinteger(none)Keep only stations with a price reported within this many hours, any whole number. Used when Maximum price age is Any age.
minPriceinteger(none)Keep stations whose cheapest reported price is at least this much.
maxPriceinteger(none)Keep stations whose cheapest reported price is at most this much.
minStarRatinginteger(any)Keep only stations rated at least this many stars.
amenitiesarray(none)Keep only stations that have ALL of the amenities you pick.
openNowOnlybooleanfalseKeep only stations GasBuddy currently reports as open.
withPricesOnlybooleanfalseKeep only stations with at least one reported price.
maxDistanceMilesinteger(none)Keep only stations within this many miles of a coordinate search.
fetchReviewsbooleanfalseAdd member reviews to each station; extra pages beyond the free first page are charged.
maxReviewsPerStationinteger10Upper bound on review rows per station, at most 1000. Up to 10 come free with the search; asking for more fetches extra pages, which are charged once per station. 0 means no reviews.
maxStationsinteger20Stop after this many matching stations across all locations. 0 means no limit.
maxPagesinteger0Stop each location after this many result pages. 0 means walk to the end.
resumeFromRunIdstring(none)Continue one interrupted run: paste its run id or dataset id.
incrementalModebooleanfalseReturn only new and changed stations on scheduled runs.
stateKeystring(none)Name or share an Incremental mode state; derived from the search when left empty.
emitUnchangedbooleanfalseIncremental mode only. Also return (and bill) unchanged stations.
emitExpiredbooleanfalseIncremental mode only. Also return (and bill) stations that disappeared.
changeScopestringallIncremental mode only. priceAndStock compares only the lowest price, its grade, the price unit and the per-grade cash price, credit price and member discount. Switching it never re-bills stations.
compactUpdatesbooleanfalseIncremental mode only. UPDATED and EXPIRED rows are slim, with priceChanges and per fuel grade variantChanges (old and new values). NEW rows stay complete.
expireAfterMissedScansinteger1Incremental mode only. Consecutive complete scans a station must be missing before it is marked EXPIRED.
ignoreFieldsForChangesarray(none)Incremental mode only. Field names (dotted paths such as prices.creditReportedBy reach into the price list) that never count as a change; they stay in the output.
proxyobjectApify Proxy, country USConnection settings; GasBuddy only answers from a North American exit.
mcpConnectorsarray(none)Optional. Send a condensed summary of each returned station to connectors you authorized under Apify Integrations (Notion, Linear, Airtable, Apify). The dataset is never changed and nothing extra is charged.
notionParentPageUrlstring(none)Notion connector only: page under which station pages are created.
maxNotifyListingsinteger50Cap on stations exported per connector per run.

Output Example

Sample shape: values are illustrative placeholders, not from a live record.

{
"stationId": "90210001",
"name": "Example Fuel Stop",
"url": "https://www.gasbuddy.com/station/90210001",
"brand": "Example Fuel Brand",
"brandId": "501",
"brandLogoUrl": "https://images.example.test/b/501.png",
"allBrands": ["Example Fuel Brand"],
"addressLine1": "400 Sample Ave",
"addressLine2": null,
"city": "Example City",
"state": "TX",
"postalCode": "00000",
"country": "US",
"latitude": 29.9012,
"longitude": -95.4123,
"phone": "555-010-0100",
"distance": "1.2mi",
"distanceMiles": 1.2,
"openStatus": "open",
"openingHours": null,
"nextOpenAt": null,
"nextCloseAt": null,
"amenities": ["C-Store", "Pay At Pump", "Air Pump"],
"amenityIds": ["c_store", "pay_at_pump", "air"],
"fuels": ["regular_gas", "midgrade_gas", "premium_gas", "diesel"],
"prices": [
{
"fuelType": "regular",
"fuelProduct": "regular_gas",
"label": "Regular",
"cashPrice": null,
"cashPostedAt": null,
"cashReportedBy": null,
"creditPrice": 3.29,
"creditPostedAt": "2026-02-01T09:00:00.000Z",
"creditReportedBy": "sample-member",
"formattedPrice": "$3.29",
"memberDiscount": 0
},
{
"fuelType": "diesel",
"fuelProduct": "diesel",
"label": "Diesel",
"cashPrice": null,
"cashPostedAt": null,
"cashReportedBy": null,
"creditPrice": null,
"creditPostedAt": null,
"creditReportedBy": null,
"formattedPrice": null,
"memberDiscount": 0
}
],
"lowestPrice": 3.29,
"lowestPriceFuelType": "regular",
"lastPriceReportedAt": "2026-02-01T09:00:00.000Z",
"lastPriceReportedBy": "sample-member",
"priceUnit": "dollars_per_gallon",
"currency": "USD",
"starRating": 4.1,
"ratingsCount": 56,
"reviewCount": 12,
"reviews": [
{
"reviewId": "sample-review-1",
"rating": 5,
"text": "Sample review text.",
"reviewedAt": "2026-01-15T00:00:00.000Z",
"agreeCount": 2,
"author": "sample-member"
}
],
"topSpotters": [
{ "name": "sample-member", "reportCount": 9, "streakDays": 3 }
],
"priceTrend": [
{ "areaName": "Example City", "country": "US", "todayAverage": 3.35, "todayLow": 3.15, "direction": "falling" }
],
"offers": [],
"cardPaymentAvailable": true,
"emergencyStatus": null,
"hasActiveOutage": false,
"isTruckFleetSite": false,
"isEnterprise": false,
"searchTerm": "Example City, TX",
"searchLocation": "Example City, TX",
"scrapedAt": "2026-02-01T12:00:00Z"
}

Plan Requirement

GasBuddy's access control is driven by geography and IP reputation: a request from outside North America (or from some hosting ranges) is refused with a challenge page. A US exit is therefore required, so keep the connection country set to US (the default); a US exit reaches the Canadian stations too, with prices in CAD per litre. The default is Apify Proxy with country US. We have not proven that every datacenter exit passes, so no run is guaranteed to need no action: if the site refuses the default exit, a residential connection gives more headroom, and you can pick it under Connection.

If the connection cannot be used, the run logs "The selected connection is unavailable to this run." followed by "Continuing on a backup connection; some pages may still be unavailable." If the account has no proxy access at all and no page can be read, the run ends with "The proxy connection was refused for this account, so no page could be read." If requests fail for another reason, it ends with "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."

FAQ

How much does it cost?

The run is billed with three events, shown on the Pricing tab: Station result (once per station row returned in the dataset), Extra review pages (once per station for which you asked for more review rows than the free first page carries; the first page never costs anything), and Actor start (once per GB of run memory, minimum one). Unchanged stations in Incremental mode, skipped stations and lookups that return no station are not billed. Use Max stations to cap the cost of any run.

Which views does the dataset have?

Besides the overview, the Prices view lists the cash and credit price per fuel grade, the Reviews view lists member reviews, and the Changes view lists changeType and changedFields of Incremental runs. A run summary is saved under the OUTPUT key of the key-value store.

This actor collects only publicly available station and price data. You are responsible for how you use it: follow GasBuddy's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Prices are reported by GasBuddy's own members and change frequently; treat this data as a snapshot, not a guarantee of the price at the pump.

Can I get only new or changed prices on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and changed stations, and unchanged ones are not billed. See the caveat above about pairing a small Max stations with Incremental mode.

Why is brand sometimes null?

GasBuddy indexes independent, unbranded stations with an empty brand list, so brand comes back null for them, and a wide search will reach them. name is still always populated for those stations, so they are never silently dropped.

Why did my run fail instead of returning an empty dataset?

If the site refuses every request, the run stops with a clear message so "no stations found" is never confused with "nothing could be read". Run it again in a few minutes, with Apify Proxy enabled and the connection country set to United States. If only some requests were refused, you still get what was found.

Why did Incremental mode bill far more stations than Max stations in one run?

See the tip above under Resume and recurring updates: Also return stations that disappeared tombstones every tracked station a complete scan did not see, and that batch is not limited by Max stations. Keep it off until you are ready for a full reconciliation run.

Can I use it with AI agents or automation tools?

Yes. Call it from any Apify integration, or trigger it from Make, Zapier, n8n or a webhook through the Integrations tab.

๐Ÿ”— More scrapers you might like

Pair this actor with these related scrapers from the same team:

โœˆ๏ธ Fuel Price Scraper
Scrape current petrol and fuel prices across Australia and New Zealand. Search by address...
๐Ÿงฉ TuneIn Scraper
Scrape TuneIn by keyword, category, genre, location or URL. Extract stations and podcasts...
๐Ÿ›’ Americanas Brazil
Scrape Americanas Brazil (americanas.com.br) by keyword, department or pasted link...
๐Ÿงฉ Suumo.jp Scraper
Scrape Suumo, Japan's largest property portal: rental rooms with rent, management fees...
๐Ÿฅฆ REWE.de Scraper
Scrape REWE Germany (rewe.de) grocery products: current price, was-price and discount...
๐Ÿ  CommercialGuru SG Property Listings & Agent Contacts Scraper
Scrape commercialguru.com.sg Singapore listings at scale. Extract prices, PSF, floor...

๐Ÿ‘‰ Browse all abotapi scrapers

๐Ÿ’ฌ Support

  • ๐Ÿž Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • ๐Ÿ› ๏ธ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • โญ Enjoying it? A quick review on the actor page helps other users find it.