How to Find EV Charging Stations in OpenStreetMap With Python

On this page

Problem statement

Electric vehicle charging stations are one of the fastest-growing kinds of point of interest, and OpenStreetMap records them with a rich set of tags: amenity=charging_station, the operator and network, the number of vehicles that can charge at once, and each socket type with its count and power. That detail is what makes OSM useful for questions such as where the fast chargers are or which networks dominate a city. It is also uneven, because a mapper can add a charging station with nothing but its location.

This page extracts every charging station in Washington, D.C. from the OpenStreetMap extract of 1 January 2026. It counts them by network and operator, tallies sockets by connector type, measures how complete each tag is, and maps where the fast chargers are.

Quick answer

Filter for amenity=charging_station, keep all tags, and reduce each feature to a point:

fp = (osmium.FileProcessor(str(PBF)).with_areas()
      .with_filter(osmium.filter.TagFilter(("amenity", "charging_station")))
      .with_filter(osmium.filter.GeoInterfaceFilter()))
E = gpd.GeoDataFrame.from_features(fp, crs=4326)
E = E[E.geom_type != "LineString"].copy()
E["geometry"] = E.to_crs(32618).representative_point().to_crs(4326)
E = E[E.within(DC)].reset_index(drop=True)
print(f"charging stations inside D.C.: {len(E)}; tag columns: {E.shape[1] - 1}")
charging stations inside D.C.: 36; tag columns: 55

OSM has 36 charging stations inside the District, with 55 different tag keys between them.

Map of the 36 OSM charging stations inside D.C., 8 with fast-charging sockets in red and 28 without in blue, sized by capacity where tagged, clustered downtown and in the north-west. Map of the 36 OSM charging stations inside D.C., 8 with fast-charging sockets in red and 28 without in blue, sized by capacity where tagged, clustered downtown and in the north-west.
Charging stations in OSM.

Networks and operators, sockets, tag completeness

1. Networks and operators

print("network:", E.get("network", pd.Series(dtype=str)).value_counts().head(6).to_dict())
print("operator:", E.get("operator", pd.Series(dtype=str)).value_counts().head(6).to_dict())
network: {'Supercharger': 4, 'ChargePoint': 1, 'FLO': 1}
operator: {'ChargePoint': 12, 'Blink': 8, 'Tesla': 3, 'EVgo': 2, 'Tesla, Inc.': 1}

operator is the better-filled key: ChargePoint operates 12 stations, Blink 8, Tesla 4 (written two ways, Tesla and Tesla, Inc.) and EVgo 2. network names Tesla's Supercharger network at 4 sites and little else.

Charging sockets recorded in OpenStreetMap in Washington, D.C., by connector. sockets tagged, by connectorNACS (Tesla)36J1772 (type1)27CCS1 (type1_combo)4CHAdeMO3010203040From the 11 of 36 stations with socket tags spatialworkflow.io
Sockets by connector.

2. Sockets by type

Socket keys follow the pattern socket:<type>=<count>, with socket:<type>:output for power. Sum them across stations:

sock_cols = [c for c in E.columns if c.startswith("socket:") and c.count(":") == 1]
counts = {c[7:]: pd.to_numeric(E[c], errors="coerce").sum() for c in sock_cols}
counts = {k: int(v) for k, v in sorted(counts.items(), key=lambda kv: -kv[1]) if v > 0}
print(f"stations with any socket tag: {E[sock_cols].notna().any(axis=1).sum()} of {len(E)}")
print("sockets by type:", counts)
stations with any socket tag: 11 of 36
sockets by type: {'nacs': 36, 'type1': 27, 'type1_combo': 4, 'chademo': 3, 'tesla_roadster': 1}

Only 11 of the 36 stations have any socket tag. Between them they record 36 NACS (Tesla) connectors, 27 J1772 (type1), 4 CCS1 (type1_combo) and 3 CHAdeMO, plus one socket for the early Tesla Roadster.

3. How complete the tags are

for tag in ("capacity", "operator", "network", "access", "fee", "opening_hours", "name"):
    share = E[tag].notna().mean() if tag in E else 0
    print(f"{tag:>13}: {share:.0%}")
     capacity: 22%
     operator: 72%
      network: 17%
       access: 14%
          fee: 39%
opening_hours: 19%
         name: 83%

Names are on 83% of stations and operators on 72%, but fee on 39%, capacity on only 22%, and network, access and opening hours on 14% to 19%. A count of sockets or a map of public access built from these tags would describe a minority of the stations.

Fast chargers in D.C.

The data used on this page

The Geofabrik OpenStreetMap extract for the District of Columbia dated 1 January 2026 (© OpenStreetMap contributors, ODbL), and the District's boundary from the US Census Bureau's 2023 cartographic boundary files at 1:500,000.

from pathlib import Path

import geopandas as gpd
import osmium
import pandas as pd
import requests

Path("data").mkdir(exist_ok=True)
def cached(path, url):
    p = Path(path)
    if not p.exists():
        r = requests.get(url, timeout=600)
        r.raise_for_status()
        p.write_bytes(r.content)
    return p
PBF = cached("data/district-of-columbia-260101.osm.pbf", "https://download.geofabrik.de/north-america/us/district-of-columbia-260101.osm.pbf")
C = gpd.read_file(cached("data/cb_2023_us_county_500k.zip", "https://www2.census.gov/geo/tiger/GENZ2023/shp/cb_2023_us_county_500k.zip"))
DC = C[C.GEOID == "11001"].to_crs(4326).geometry.iloc[0]
print("boundary loaded")
boundary loaded

The District boundary is loaded for filtering.

Example 1: fast chargers

DC fast chargers use CCS (socket:type1_combo), CHAdeMO or Tesla's connectors. Find the stations with any of them:

fast_cols = [c for c in ("socket:type1_combo", "socket:chademo", "socket:tesla_supercharger", "socket:nacs") if c in E]
fast = E[E[fast_cols].notna().any(axis=1)] if fast_cols else E.iloc[0:0]
print(f"stations with a fast-charging socket tag: {len(fast)} of {len(E)}; columns used: {fast_cols}")
print("their networks:", fast.get("network", pd.Series(dtype=str)).value_counts().head(5).to_dict())
stations with a fast-charging socket tag: 8 of 36; columns used: ['socket:type1_combo', 'socket:chademo', 'socket:nacs']
their networks: {'Supercharger': 4, 'FLO': 1}

8 stations have a CCS, CHAdeMO or NACS socket tag; 4 of them are Tesla Superchargers. The 25 stations with no socket tags may include fast chargers too, which is why fast-charger maps from OSM need a completeness check.

Share of charging stations in D.C. carrying each tag. tag completeness, 36 stationsshare taggedname83%operator72%fee39%capacity22%opening_hours19%network17%access14%Only 11 stations have any socket tag spatialworkflow.io
Tag completeness.

One feature per site

The layers of detail OpenStreetMap can record for a charging station. what a station can recordsocket:<type>:outputpower per connectoroptional toosocket:<type>connectors and counts11 of 36capacityvehicles at once8 of 36amenity=charging_stationthe site36 inside D.C.Each layer is optional spatialworkflow.io
What a station can record.

A charging station in OpenStreetMap is a node or an area tagged amenity=charging_station, usually one feature for a whole site rather than one per charger. capacity gives the number of vehicles that can charge at once. The socket:* keys describe connectors: socket:type1 for J1772, the North American AC standard, socket:type1_combo for CCS1 fast charging, socket:chademo, and socket:tesla_supercharger or socket:nacs for Tesla's connector, each with the number of sockets and, under :output, the power. network, operator and brand identify who runs it, and access, fee and opening_hours say who can use it and when.

Because each of those tags is optional, analyses depend on how completely they are filled in, and charging stations change fast, as networks open sites, rebrand and upgrade connectors. Counting stations is usually reliable; counting sockets or power is only as good as the share of stations that have socket tags. Before comparing cities or networks, measure tag completeness. Where possible, compare with an official register, such as the US Department of Energy's Alternative Fuels Data Center.

Sites against chargers, and Tesla connectors

Checks before using OpenStreetMap charging station data. before mapping chargerssites or chargers?check close duplicatessocket coverage11 of 36 stationsnacs and tesla_superchargersame connector, two tagsaccess=privatenot publicofficial registercompare with AFDCD.C., OSM extract of 1 January 2026 spatialworkflow.io
Before mapping chargers.
  • Sites and chargers: some mappers add one node per charger; check for clusters of stations a few metres apart before counting sites.
  • Private chargers: access=private or customers marks chargers not open to the public.
  • Socket values: counts are usually integers, but yes appears; pd.to_numeric(..., errors="coerce") skips it.
  • Tesla connectors: socket:nacs is newer tagging for the same connector as socket:tesla_supercharger; check both.

FAQ

How do I find EV charging stations in OpenStreetMap?

Filter for amenity=charging_station in an extract or with the Overpass API, and keep all tags to get sockets, network and capacity.

What do the socket tags mean in OSM?

socket:<type> gives the number of sockets of that connector type, for example socket:type1_combo=2 for two CCS1 connectors; socket:<type>:output gives the power.

How do I find fast chargers in OSM?

Look for socket:type1_combo (CCS), socket:chademo or socket:tesla_supercharger and socket:nacs tags.

Is OSM charging station data complete?

Station locations usually are in cities; socket and power details are often missing, so measure their coverage before using them.