Complete Guide: How to Scrape supercharge.info Using Supercharger Database Scraper
Run the Supercharger Database Scraper Apify Actor from Python and get every supercharge.info site as typed JSON: status, stalls, kW, plugs, coordinates.

This complete guide to Supercharger Database Scraper shows how to scrape Supercharger sites from supercharge.info with Python through the Apify API, and get back one typed row per site: status, stall count, maximum power in kW, stall types, plug mix, the open-to-non-Tesla flag, opening date, coordinates, and links to PlugShare, OpenStreetMap and Google Maps.
supercharge.info is a community-run tracker of Tesla Supercharger sites. It lists more than open sites: ask for CONSTRUCTION, PERMIT or PLAN and you get sites being built, permitted or announced. Its data is maintained by its contributors, so it is not a Tesla source. The Actor is unofficial and not affiliated with Tesla or supercharge.info.
You will configure the Supercharger Database Scraper Apify Actor (reventadata/supercharge-scraper), run it from Python, read its rows and use its filters. Prerequisites: Python 3.11+, the apify-client package and an Apify API token. Expect one sitting. The sample row in this guide is a sample from a capture dated 2026-10-12, parsed with the Actor's own code; this guide quotes no run of its own.
TL;DR
In this tutorial, you'll learn how to export supercharge.info with the Supercharger Database Scraper Apify Actor from Python. Key steps: install apify-client, export APIFY_API_TOKEN, set country, region and statuses, optionally minStalls, minPowerKw, openToNonTeslaOnly or searchText, call reventadata/supercharge-scraper, and read the rows from the run's default dataset.
Expected outcome: a JSON list of sites with nested stalls and plugs counts and ready-made map links, ready for a spreadsheet, a map layer or a database.
The Actor: apify.com/reventadata/supercharge-scraper.
Prerequisites and setup
You will need:
- Python 3.11+ (
apify-client3.3.0 requires it). - The Apify API client for Python.
- An Apify account. Apify Console is Apify's web interface; your API token is on its API & Integrations page. The platform documentation starts at docs.apify.com.
Install the client:
pip install "apify-client~=3.0"
The token is a secret. Apify's docs advise giving each token a description and never using one token for several services. The code in this guide reads it from the environment, so it never sits in a script or a commit.
Set the token in your environment:
export APIFY_API_TOKEN="your_apify_token_here"
Understanding Supercharger Database Scraper
What it does and how it works
- One download. The Actor requests supercharge.info's full site list in one GET. The source publishes it as plain JSON, and it served it to direct requests, with no proxy, when measured on 2026-09-22. The proxy is off by default.
- Local filters. Your
country,region,statuses, stall, power, non-Tesla and text filters run on that list, inside the Actor. - Row shaping. Each matching site becomes one flat row with nested
stallsandplugs. The Actor resolves the parking type id into its name and builds links: Google Maps from the coordinates, PlugShare and OpenStreetMap from their ids, Tesla's Find Us page from the location id, and the supercharge.info forum thread when the source flags one. - Saving. The first
maxItemsmatches are saved, in the order the source lists them.
Limitations
- No prices: supercharge.info does not publish them.
- No live availability: rows carry stall counts and site status, not how many stalls are free.
- Statuses and details are the community's; the Actor passes them through unchanged.
Step-by-step walkthrough
Step 1: Initialize the client and define inputs
country takes the country as the source names it (Spain, France, USA, United Kingdom), matched in full and ignoring case. region takes Europe, North America, Asia Pacific or South America. statuses takes any of OPEN, EXPANDING, CONSTRUCTION, PERMIT, PLAN, VOTING, CLOSED_TEMP, CLOSED_PERM; left unset it means OPEN only, and an empty list means every status. maxItems (default 100) caps saved sites.
This setup asks for open sites in Spain with at least 8 stalls and saves at most 50:
import os
from apify_client import ApifyClient
# 1. Initialize ApifyClient with the token from the environment
client = ApifyClient(os.environ["APIFY_API_TOKEN"])
# 2. Define the filters: open sites in Spain with at least 8 stalls
run_input = {
"country": "Spain",
"statuses": ["OPEN"],
"minStalls": 8,
"maxItems": 50,
}
Two more configurations, as JSON input:
- Europe's build pipeline:
{"region": "Europe", "statuses": ["CONSTRUCTION", "PERMIT", "PLAN"], "maxItems": 500}. - Every status, worldwide, up to 1,000 sites:
{"statuses": [], "maxItems": 1000}.
Step 2: Configure filters
minStalls: at least N stalls (0 = off). Sites with an unknown count are kept.minPowerKw: maximum site power of at least N kW (0 = off). Unknown power is kept.openToNonTeslaOnly: only sites where non-Tesla EVs can charge.searchText: text the site's name, street, city, state, ZIP or country must contain, ignoring case.
A status outside the eight known values stops the run with an error that lists them.
Step 3: Run the Actor
.call() starts the run and waits for it to finish:
# 3. Start the Actor run and wait for it to finish
print("Starting supercharge.info extraction...")
run = client.actor("reventadata/supercharge-scraper").call(run_input=run_input)
if run is None or run.status != "SUCCEEDED":
status = run.status if run else "unknown"
raise SystemExit(f"Run did not succeed (status: {status}).")
# 4. Fetch the saved sites
items = client.dataset(run.default_dataset_id).list_items().items
print(f"Retrieved {len(items)} sites.\n")
Step 4: Process the rows
for item in items:
print(item["name"])
print(f" Status: {item.get('status')}")
print(f" Stalls: {item.get('stallCount')} Max power: {item.get('powerKilowatt')} kW")
print(f" Plugs: {item.get('plugs')}")
print(f" Open to non-Tesla EVs: {item.get('otherEVs')}")
print(f" Map: {item.get('googleMapsUrl')}")
print("-" * 40)
Step 5: Inspect a real row
A sample from a capture dated 2026-10-12, parsed with the Actor's own code. It is an open Spanish site with 12 stalls, so it passes the filters above. A saved row also carries scrapedAt, added at save time:
{
"id": 8734,
"name": "Rivas Vaciamadrid, Spain",
"url": "https://supercharge.info/map?siteID=8734",
"status": "OPEN",
"statusDays": 0,
"address": "C. Marie Curie, 4",
"city": "Rivas-Vaciamadrid",
"state": "Madrid",
"postalCode": "28521",
"country": "Spain",
"region": "Europe",
"latitude": 40.335907,
"longitude": -3.524279,
"elevationMeters": 564,
"stallCount": 12,
"powerKilowatt": 250,
"stalls": {
"v4": 12,
"accessible": 2,
"trailerFriendly": 5
},
"plugs": {
"ccs2": 12
},
"solarCanopy": false,
"battery": false,
"otherEVs": true,
"facilityName": null,
"dateOpened": "2025-03-27",
"locationId": "32352",
"countedInTotals": true,
"hours": null,
"facilityHours": null,
"accessNotes": null,
"addressNotes": "C.C. H2Ocio",
"plugshareId": 742461,
"osmId": 12590063608,
"parkingId": null,
"parkingType": null,
"googleMapsUrl": "https://www.google.com/maps/search/?api=1&query=40.335907%2C-3.524279",
"plugshareUrl": "https://www.plugshare.com/location/742461",
"osmUrl": "https://www.openstreetmap.org/node/12590063608",
"teslaFindUsUrl": "https://www.tesla.com/findus?location=32352",
"forumUrl": "https://supercharge.info/service/supercharge/discuss?siteId=8734"
}
Step 6: Export
Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL, from Console or through the API's format parameter.
Working with the API
The Python client gives two ways to start this Apify Actor. client.actor("reventadata/supercharge-scraper").call(run_input=run_input) starts the run and waits for it to finish before returning the run object, or None; that is what the code above uses. For a job queue, .start(run_input=run_input) returns the run object at once, and you read it back later with its ID.
Authentication is the API token in APIFY_API_TOKEN; keep it out of source control. Once a run finishes, client.dataset(run.default_dataset_id).list_items().items returns the rows in one call, and iterate_items() streams them for larger datasets, such as a worldwide export. Both accept fields if you want only some columns.
For event-driven pipelines, attach a webhook for the ACTOR.RUN.SUCCEEDED event. Its payload's resource is the response of the Get Actor run API endpoint, so it carries defaultDatasetId, and your handler can fetch the rows without polling.
Error handling: check run.status as the code does. A finished run ends as SUCCEEDED, FAILED, TIMED-OUT or ABORTED. A run that saves no rows ends SUCCEEDED when the download loaded normally but nothing matched, and FAILED only if the download was unreadable or blocked. When a run fails, read its log from Python with client.log(run.id).get(). It says how many sites the download held (World dump: N site(s).), how many passed your filters (Filters matched N site(s).) and how many were saved (Run completed. Pushed N rows.).
Limits: the account's memory and concurrent-run limits apply to every start. call() accepts wait_for_resources, which keeps retrying the start while the API rejects it for either limit.
Advanced usage patterns
Batch processing several countries
Each run takes one country. Since every run downloads the full list anyway, the simplest batch is one run with country empty and a region, or no filter at all, then split the rows by country in your own code. For a few named countries, loop over them in Python and start one run per country.
Scheduled runs
Save the input as a task and add an Apify schedule. Schedules run an Actor or task on a cron expression; 0 8 * * * is every day at 8 AM.
Monitoring the build pipeline
Schedule a run with statuses: ["CONSTRUCTION", "PERMIT", "PLAN", "OPEN"] and keep each dataset. Join consecutive datasets on id, which is stable per site, and list every site whose status changed: a permit becoming construction, construction becoming open. statusDays shows how long a site has sat in its current status. Pair the schedule with a webhook on ACTOR.RUN.SUCCEEDED to load each new dataset as it lands.
Volume control
maxItems is the one bound on output. The filters only decide which sites are saved, never how much is downloaded, so a narrow filter adds no extra requests. For a first test, maxItems: 10 matches the Actor's own prefill.
Understanding your data
Key fields and how to read them:
status,statusDays: status as the source gives it, and days in it.Kozina, Slovenia (old)in the capture hadCLOSED_PERMand 2200 days.stallCount,powerKilowatt: total stalls and maximum site power. In the five captured sites, power was 250, 150 or 72 kW.stalls: types (v2,v3,v4,urban) plusaccessibleandtrailerFriendlycounts.plugs: standards (nacs,ccs1,ccs2,tpc,gbt,type2,multi). The two US sites captured hadtpconly; the European ones hadccs2.otherEVs: open to non-Tesla cars. 2 of the 5 captured sites had it, both 250 kW V4 sites in Europe.parkingType: the source's parking type name, such asFree initially; null when the source gives none, as for 2 captured sites.hours,accessNotes,addressNotes: free text. 3 of the 5 captured sites hadhours.countedInTotals: whether the source counts the site in its network totals.
Troubleshooting guide
- Zero rows: a run that matches no site ends SUCCEEDED with an empty dataset; it ends FAILED only if the download was unreadable or blocked. Check
countryandregionspelling against the source's names:USA, notUnited States. The match is on the whole name, ignoring case. - Run stops with an error about statuses: a value in
statusesis not one of the eight known ones. The error lists them. - Only open sites:
statuseswas left unset, which meansOPENonly. Pass[]for all. - A site below
minStallscame through: its stall count is unknown, and unknown counts are kept. The same holds forminPowerKw. searchTextmatched more than expected: it also searches the state and ZIP.madridmatches every site in the state of Madrid, not only the city.- No prices or free-stall counts: the source has none.
- Reading the log:
client.log(run.id).get(); theFilters matchedline shows how many sites passed beforemaxItemscut.
For help, use the Actor's Store page.
Best practices
- Filter in the Actor, not after. Rows that fail a filter are never saved, so set
country,statusesand the stall or power floors up front. - Always set
maxItems. It is the bound on rows saved. Raise it on purpose for worldwide exports. - Start small. A low
maxItemsuntil your code handles the nestedstallsandplugs. - Treat nulls as unknown. A null
stallCountorparkingTypemeans the source has no value, not zero. - Mind freshness. Statuses change as sites are built. Schedule reruns instead of reusing old datasets.
- Handle failure explicitly. Check
run.statusbefore reading rows.
Pricing
For current pricing and details, see the Store page.
Conclusion and next steps
You configured Supercharger Database Scraper, ran it from Python and read typed site rows with stall types, plugs, power and map links. Next: schedule the export, attach a webhook, or track the build pipeline across datasets.
Try Supercharger Database Scraper yourself and let me know what you build!
About the author: reventadata builds and maintains marketplace and data scrapers on the Apify Store.
Resources
About the author
- Hi, I’m the engineer behind ReventaData. I build automated web scrapers, reverse-engineer undocumented APIs, and design data pipelines on Apify that turn complex, unstructured websites into clean, reliable feeds. Here on Hashnode, I share practical tutorials on modern web scraping with Python, bypassing aggressive anti-bot protections (Cloudflare, Akamai, PerimeterX), and data pipeline automation, reverse-engineering hidden endpoints, and automating data extraction. Explore our turnkey scrapers: https://apify.com/reventadata
Comments
Join the discussionNo comments yet. Be the first to comment.



