# Open Charge Map EV Station Search (`ryanclinton/open-charge-map`) Actor

Search and extract electric vehicle charging station data from [Open Charge Map](https://openchargemap.org) -- the world's largest open registry of EV charging locations with over 300,000 stations across 100+ countries.

- **URL**: https://apify.com/ryanclinton/open-charge-map.md
- **Developed by:** [Ryan Clinton](https://apify.com/ryanclinton) (community)
- **Categories:** AI, Developer tools
- **Features:** Limited permissions
- **Stats:** 14 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 station fetcheds

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

## Open Charge Map — EV Infrastructure Planning & Scenario Intelligence

*An EV infrastructure intelligence layer for Open Charge Map -- it turns open charger data into infrastructure decisions.*

![Open Charge Map EV Infrastructure Intelligence](https://apifyforge.com/readme-assets/ryanclinton-open-charge-map/hero.png)

**Find chargers, identify infrastructure gaps, and model EV network resilience -- from a single API call.**

Turn [Open Charge Map](https://openchargemap.org) data (over 300,000 stations across 100+ countries) into charger recommendations, infrastructure-gap analysis, site-selection opportunities, route-readiness assessments, and network-resilience models. Raw Open Charge Map tells you where chargers are. This actor tells you what to do about it:

- ✓ Which stations are dependable
- ✓ Whether a route is viable end to end
- ✓ Where charging infrastructure is missing
- ✓ Which operators dominate an area (and the risk if one fails)
- ✓ Where chargers should be built next
- ✓ What happens if part of the network goes down

All deterministic -- no LLM, no AI inference, fully reproducible. Requires a free Open Charge Map API key, or run in dry-run mode to see the output shape without one.

```text
            Open Charge Map
                  │
                  ▼
           Raw station data
                  │
                  ▼
            This Actor
                  │
   ┌──────────────┼───────────────┐
   ├─ Station recommendations      │
   ├─ Coverage-gap detection       │
   ├─ Candidate sites (where to build)
   ├─ Critical-node detection      │
   ├─ Route-corridor readiness     │
   ├─ Resilience + fragility models│
   └─ Scenario simulation          │
```

***

### Questions this actor answers

Buyers think in questions, not features. This actor answers them in a single call:

- **Can drivers reliably charge in this area?** → `evReadinessScore`, `coverageGrade`, `infrastructureProfile`
- **Where should chargers be built next?** → `recordType: "candidate-site"` and `recordType: "opportunity"`
- **What happens if an operator's network fails?** → `recordType: "simulation"` (`removeOperator`)
- **Which stations are critical to a route?** → `recordType: "critical-node"`
- **Where are the charging deserts?** → `recordType: "coverage-gap"` and `recordType: "heat-zone"`
- **How does this area compare to others?** → `compareAreas` → `recordType: "area-comparison"`, plus an account-scoped `benchmark` percentile
- **Is the network growing?** → name a `watchlistName` for growth and trend across scheduled runs

***

![What you get: candidate sites, scenario modelling, GIS heat zones, infrastructure twin](https://apifyforge.com/readme-assets/ryanclinton-open-charge-map/feature-callouts.png)

### Open Charge Map gives you data. This gives you decisions.

Most EV data products are datasets. This is a decision engine. Compare what each one actually answers:

| Business question | Open Charge Map | Typical EV dataset | This actor |
|---|:---:|:---:|:---:|
| Where are the chargers? | ✓ | ✓ | ✓ |
| Which chargers should I trust? | ✗ | ✗ | ✓ |
| Is this route viable end to end? | ✗ | Partial | ✓ |
| Where should chargers be built next? | ✗ | ✗ | ✓ |
| What happens if an operator fails? | ✗ | ✗ | ✓ |
| Which stations are network-critical? | ✗ | ✗ | ✓ |
| Is this area EV-ready? | ✗ | ✗ | ✓ |

**Raw Open Charge Map** returns `{ "title": "...", "powerKW": 150, "statusType": "Operational" }`. **This actor** returns `{ "recommendation": "recommended", "confidence": 92, "routeReady": true, "operatorReliability": "excellent", "infrastructureProfile": "mature-balanced" }` plus run-level planning records the raw API never gives you. It is a charging-infrastructure decision layer, not a station list.

***

### Decisions produced in a single run

One call returns a complete set of infrastructure decisions, not raw rows:

- ✓ EV-readiness assessment
- ✓ Infrastructure-health assessment (profile, resilience, fragility)
- ✓ Route-viability assessment
- ✓ Site-selection recommendations
- ✓ Coverage-gap detection
- ✓ Operator-risk analysis
- ✓ Network-resilience assessment
- ✓ Infrastructure-change simulations

***

### Outputs you cannot get from Open Charge Map

These record types are the product, not implementation details:

- **`infrastructure-twin`** -- one dashboard-ready record modelling the whole network (archetype, readiness, resilience, fragility, zones, dominant operator).
- **`opportunity`** -- tells you where charging supply falls short, scored and mappable.
- **`coverage-gap`** -- tells you where fast/rapid charging is missing, with centre, radius, and severity.
- **`candidate-site`** -- tells you where a new charger should be built to close a corridor gap, with recommended type.
- **`critical-node`** -- tells you which stations would break route coverage if they failed, with a dependency score.
- **`simulation`** -- tells you what happens if an operator's network fails or you add rapid chargers (before/after EV-readiness and resilience).
- **`heat-zone`** -- GIS-ready zones (opportunity / coverage / risk / density) you can plot directly in Kepler, Mapbox, or ArcGIS.

***

### The Infrastructure Twin: an entire EV network in one record

Instead of analysing hundreds of stations by hand, you read one `infrastructure-twin` record and understand the whole region at a glance:

```json
{
    "archetype": "rapid-deficient",
    "evReadinessScore": 62,
    "resilienceIndex": 44,
    "fragilityIndex": 28,
    "opportunityScore": 71,
    "coverageZones": 5,
    "criticalNodes": 0,
    "opportunityZones": 3,
    "candidateSites": 2,
    "dominantOperator": "Tesla",
    "concentrationRisk": "high"
}
```

That single row tells a planning team: this is a rapid-deficient, operator-concentrated network with moderate readiness, real fragility, and three opportunity zones where two candidate sites already pinpoint the highest-impact builds. It is the row a dashboard binds to.

***

### 30 seconds from raw data to infrastructure decisions

Input -- one search:

```json
{ "latitude": 51.5074, "longitude": -0.1278, "distance": 25, "apiKey": "YOUR_OCM_API_KEY" }
```

The run summary tells you, in one record:

```json
{
    "evReadinessScore": 81,
    "coverageGrade": "A",
    "infrastructureProfile": "mature-balanced",
    "coverageGap": true,
    "opportunityScore": 64,
    "candidateSiteCount": 1,
    "resilienceIndex": 73
}
```

In one call you know: is the area EV-ready, are there charging deserts, where new chargers would help most, and how resilient the network is -- without building any of that analysis yourself.

***

### Who should (and should not) use this

**This is for you if you need infrastructure decisions:**

- **EV charging operators** -- expansion opportunities, network-failure modelling, coverage benchmarking
- **Fleet managers** -- route viability, reliable charging corridors, critical charging dependencies
- **Property developers & site selectors** -- charger deserts, candidate-location comparison, EV-readiness scoring
- **GIS & planning teams** -- coverage gaps, clusters, opportunity zones, and heat zones straight into a map
- **Researchers & policy** -- infrastructure equity, density, and resilience across regions

**It is probably not for you if** you only need raw charger coordinates, or you already have your own EV planning models -- in that case the raw [Open Charge Map API](https://openchargemap.org) is all you need.

***

### Example: spotting a charger desert in one run

```text
Search area:      Birmingham, 25 km radius
Returned:         43 stations
EV-readiness:     62 / 100 (grade C)
Infrastructure:   rapid-deficient
Coverage gaps:    3
Candidate sites:  2
Opportunity:      81 / 100
```

A planning team reads this in seconds: the area has chargers but is rapid-deficient, three coverage gaps exist, and the actor has already pinpointed two candidate sites where new rapid chargers would have the greatest impact -- the exact analysis that otherwise takes a GIS analyst days.

The same run shape produces very different verdicts by area:

| | Rural county | Major city | Highway corridor |
|---|---|---|---|
| EV-readiness | 31 / 100 | 88 / 100 | 71 / 100 |
| Profile | `rural-sparse` | `mature-balanced` | (corridor) |
| Coverage gaps | 6 | 0 | -- |
| Candidate sites | 4 | 0 | -- |
| Critical nodes | -- | -- | 2 |
| Route-ready | -- | -- | yes |

One actor, one input shape, three completely different infrastructure decisions: invest heavily in the rural county, maintain the city, and protect two critical stations on the corridor.

***

### Why infrastructure teams use this actor

Raw charger data and this actor answer different questions:

| Raw charger data answers | This actor answers |
|---|---|
| "Where are the chargers?" | "Where should infrastructure investment go?" |
| "How many chargers exist?" | "Is the network resilient if one fails?" |
| "Which operators are present?" | "What happens if the dominant one disappears?" |
| "What's the power rating?" | "Which chargers can I actually depend on?" |
| "Is there a charger on this road?" | "Can a driver complete this route end to end?" |

It runs in the Apify cloud (no servers, automatic retry and backoff), outputs a clean flat JSON schema ready for Google Sheets / Slack / webhooks / Zapier / Make and any of Apify's 100+ integrations, exports as JSON / CSV / Excel, and can be scheduled to track a region over time.

***

### The analytics engine

Each layer adds decisions on top of the raw Open Charge Map data:

```text
Raw Open Charge Map data
        │
        ▼  Station Intelligence      → which chargers to trust
        ▼  Route Intelligence        → whether a journey works
        ▼  Infrastructure Intelligence → how healthy the network is
        ▼  Planning Intelligence     → where to build next
        ▼  Scenario Intelligence     → what happens if it changes
        │
        ▼
   Infrastructure decisions
```

![The intelligence stack the actor adds on top of raw Open Charge Map data](https://apifyforge.com/readme-assets/ryanclinton-open-charge-map/intelligence-layers.png)

#### Station Intelligence (per charger)

- **Quality score + confidence** -- a deterministic 0-100 `stationScore` (speed + availability + verification + redundancy) and a separate 0-100 data-trust `confidence` (verification recency + metadata completeness).
- **Charging tier + vehicle compatibility** -- `chargingTier` (rapid / fast / standard / slow) plus `teslaCompatible` / `ccsCompatible` / `chademoCompatible` / `type2Compatible` / `j1772Compatible`.
- **Reliability signals** -- `operatorReliability` tier, `singlePointOfFailure` flag, `accessComplexity`, `powerConfidence`, and within-result `percentiles`.
- **Actionable recommendation** -- a stable `recommendation` enum (`recommended` / `usable` / `caution` / `avoid` / `planned`) + a `routeReady` boolean agents branch on.

#### Route Intelligence (per journey)

- **Route-corridor readiness** -- supply start/end coordinates and the actor samples the corridor, returning `routeReady`, `corridorReadiness`, longest gap, weak/critical segments, and recommended stops.
- **Critical nodes** -- `recordType: "critical-node"` flags the single stations a corridor depends on, with a `dependencyScore`: lose one and the route re-breaks.

#### Infrastructure Intelligence (per area)

- **One-glance profile + scores** -- a single `infrastructureProfile` archetype, plus `evReadinessScore`, `coverageGrade` (A+ to F), `resilienceIndex`, and `fragilityIndex`.
- **Operator + density analysis** -- `concentrationRisk` (HHI + top-operator share), `catchment` overlap, geographic clusters, and multi-radius coverage (5 / 10 / 25 / 50 km from one search).
- **Dashboard + GIS records** -- one `recordType: "infrastructure-twin"` for the whole network, `recordType: "heat-zone"` records for Kepler/Mapbox/ArcGIS, and an account-scoped `benchmark` percentile.

#### Planning Intelligence (where to build)

- **Opportunity + candidate sites** -- `opportunityScore` + `investmentPotential` with discrete `recordType: "opportunity"` records, and `recordType: "candidate-site"` records pinpointing where new chargers should go.
- **Coverage gaps** -- mappable `recordType: "coverage-gap"` records (centre, radius, missing infrastructure, severity).
- **Site selection + growth** -- `compareAreas` ranks 2-8 areas (`recordType: "area-comparison"`); a `watchlistName` tracks growth and trend across scheduled runs.

#### Scenario Intelligence (what if)

- **Scenario simulation** -- `simulate` an operator failure, a top-10% outage, or new rapid chargers, and get a `recordType: "simulation"` with before/after EV-readiness and resilience.
- **Analysis modes** -- `analysisMode` (coverage / planning / route / investment / competition / benchmark) frames the run around your job.

#### Search, filters & operations

- Search over 300,000 stations across 100+ countries by coordinates + radius; filter by `countryCode`, `operatorId` / `operatorName`, connector type, charging level, status, `minPowerKW`, and `minConfidence`.
- `outputProfile` (full / standard / minimal), `resolveReferenceData` for ID lookups, up to 500 results per run, automatic retry with backoff, and a dry-run demo mode without a key.

***

### How to use Open Charge Map EV Stations

#### Using the Apify Console

1. Go to the [Open Charge Map EV Stations](https://apify.com/ryanclinton/open-charge-map) actor page on Apify.
2. Click **Start** to open the input configuration form.
3. Enter your **API Key** -- register a free key at [openchargemap.org](https://openchargemap.org) (sign in, then My Profile > My Apps > Register Application). Or leave it blank to run in dry-run mode with sample data.
4. Set your **search location** by entering latitude and longitude coordinates (e.g., 40.7128 and -74.006 for New York City).
5. Configure the **search radius** -- set the distance value and choose Miles or KM.
6. Optionally apply filters for country code, connector type, charging level, operator, or station status.
7. Set **max results** (up to 500) and click **Start**.
8. When the run finishes, download results from the **Dataset** tab as JSON, CSV, or Excel.

#### Using the Apify API or CLI

```bash
apify call ryanclinton/open-charge-map \
  --input='{
    "latitude": 37.7749,
    "longitude": -122.4194,
    "distance": 5,
    "distanceUnit": "Miles",
    "maxResults": 100,
    "levelId": 3,
    "statusTypeId": 50,
    "apiKey": "YOUR_API_KEY"
  }'
```

This example searches for up to 100 operational DC Fast Charging stations within 5 miles of downtown San Francisco.

***

### Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `latitude` | Number | No | 40.7128 (prefill) | Latitude of the search center point. Use Google Maps or a geocoding service to find coordinates. |
| `longitude` | Number | No | -74.006 (prefill) | Longitude of the search center point. Pair with latitude for location-based search. |
| `distance` | Number | No | 10 | Search radius from the center point, in the unit specified by `distanceUnit`. |
| `distanceUnit` | String | No | Miles | Unit for the search radius. Options: `Miles` or `KM`. |
| `countryCode` | String | No | -- | ISO 2-letter country code to filter results (e.g., `US`, `GB`, `DE`, `FR`, `JP`). Leave empty for all countries. |
| `maxResults` | Integer | No | 50 | Maximum number of stations to return. Range: 1--500. |
| `operatorId` | Number | No | -- | Filter by charging network operator ID (e.g., 23 for Tesla, 5 for ChargePoint). |
| `operatorName` | String | No | -- | Filter by operator name instead of ID (e.g., `Tesla`, `ChargePoint`). Resolved to the operator ID via Open Charge Map reference data. |
| `connectionTypeId` | Number | No | -- | Filter by connector type ID. Common values: 1=Type 1, 25=Type 2, 32=CCS Type 1, 33=CCS Type 2, 2=CHAdeMO, 27=Tesla Supercharger. |
| `levelId` | Number | No | -- | Filter by charging level. Values: 1=Level 1, 2=Level 2, 3=DC Fast Charging. |
| `statusTypeId` | Number | No | -- | Filter by station status. Values: 50=Operational, 100=Not Operational, 150=Planned. |
| `minPowerKW` | Integer | No | -- | Only return stations whose fastest connector is at least this many kW. Stations with no published power are excluded when set. Use 50 for fast/rapid only, 150 for ultra-rapid. |
| `minConfidence` | Integer | No | -- | Only return stations whose data-trust confidence score (0-100) is at least this value. Use 70-80 to exclude stale or sparse listings. |
| `sortBy` | String | No | distance | Result order: `distance` (nearest first), `power` (fastest first), `score` (highest quality first), or `confidence` (most trusted first). |
| `outputProfile` | String | No | full | Detail per record: `full` (all fields incl. raw connections), `standard` (decision fields, no raw connections), or `minimal` (core location + decision fields only). |
| `startLatitude` | Number | No | -- | Route mode: latitude of the journey start. Provide all four route coordinates to enable route-corridor analysis. |
| `startLongitude` | Number | No | -- | Route mode: longitude of the journey start. |
| `endLatitude` | Number | No | -- | Route mode: latitude of the journey end. |
| `endLongitude` | Number | No | -- | Route mode: longitude of the journey end. |
| `routeMaxGapKm` | Integer | No | 120 | Route mode: the longest stretch (km) without a route-ready charger you consider acceptable. Longer gaps are flagged critical. |
| `routeSampleKm` | Integer | No | 50 | Route mode: distance between sampled waypoints (km). Capped at 30 waypoints total. |
| `resolveReferenceData` | Boolean | No | false | Emit a `reference-data` record listing every operator, connector, level, and status with its numeric ID, so you can look up the IDs the filters expect. |
| `corridorName` | String | No | -- | Route mode: optional label for the corridor (e.g. `London-Birmingham`) used in the route-analysis record. |
| `compareAreas` | Array | No | -- | Provide 2-8 areas (`{ label, latitude, longitude, distance }`) to rank them by EV-readiness and opportunity. Emits an `area-comparison` record. One extra query per area. |
| `watchlistName` | String | No | -- | Name a watchlist to track infrastructure growth and trend across scheduled runs. Reports new stations, new rapid chargers, EV-readiness change, and growth trend since the last run. |
| `analysisMode` | String | No | auto | Frame the run around a job: `coverage` / `planning` / `route` / `investment` / `competition` / `benchmark`. Tunes the default sort. Auto-resolved from your input when blank. |
| `simulate` | Object | No | -- | What-if modelling: `{ "removeOperator": "Tesla" }`, `{ "removeTopPercent": 10 }`, or `{ "addRapidChargers": 5 }`. Emits a `simulation` record per scenario with before/after EV-readiness and resilience. |
| `apiKey` | String | Recommended | -- | Your Open Charge Map API key. Register free at openchargemap.org. Without a key, the actor runs in dry-run mode with sample data. |

#### Example input (JSON)

```json
{
    "latitude": 51.5074,
    "longitude": -0.1278,
    "distance": 3,
    "distanceUnit": "KM",
    "countryCode": "GB",
    "maxResults": 200,
    "levelId": 3,
    "statusTypeId": 50,
    "apiKey": "YOUR_API_KEY"
}
```

#### Tips for configuring input

- **Start with a smaller radius** (5--10 miles/km) and increase if you need broader coverage. Larger radii return more results but may include distant stations.
- **Use `levelId: 3`** to find only DC Fast Charging stations suitable for long-distance travel or fleet vehicles.
- **Combine country code with coordinates** in border areas to ensure results stay within your target country.
- **Omit coordinates** and provide only a country code to get a general sample of stations from that country (results will not be distance-sorted).

***

### Output

![Sample scored station output: tier, score, confidence, recommendation, route-ready](https://apifyforge.com/readme-assets/ryanclinton-open-charge-map/output-table.png)

Each run produces an Apify dataset of `recordType: "station"` records (one per charging station) followed by one `recordType: "summary"` record ranking the area. Here is an example station record:

```json
{
    "recordType": "station",
    "schemaVersion": "2.5.0",
    "stationId": 148231,
    "title": "ChargePoint - Manhattan West Parking",
    "street": "385 9th Ave",
    "city": "New York",
    "state": "NY",
    "postcode": "10001",
    "country": "United States",
    "countryCode": "US",
    "latitude": 40.7537,
    "longitude": -73.9981,
    "operatorName": "ChargePoint",
    "operatorWebsite": "https://www.chargepoint.com/",
    "connections": [
        {
            "type": "Type 2 (Socket Only)",
            "level": "Level 2 : Medium (Over 2kW)",
            "powerKW": 7.2,
            "quantity": 4,
            "currentType": "AC (Single-Phase)"
        },
        {
            "type": "CCS (Type 1)",
            "level": "Level 3 : High (Over 40kW)",
            "powerKW": 62.5,
            "quantity": 2,
            "currentType": "DC"
        }
    ],
    "connectorTypes": ["CCS (Type 1)", "Type 2 (Socket Only)"],
    "numberOfPoints": 6,
    "usageCost": "$0.35/kWh",
    "accessComments": "Parking garage, open 24/7. EV charging on Level B1.",
    "statusType": "Operational",
    "isRecentlyVerified": true,
    "dateLastVerified": "2025-11-15T08:30:00Z",
    "distance": 2.41,
    "distanceUnit": "Miles",
    "url": "https://openchargemap.org/site/poi/details/148231",
    "extractedAt": "2026-02-19T14:22:33.000Z",
    "maxPowerKW": 62.5,
    "chargingTier": "fast",
    "reliability": {
        "verified": true,
        "operational": true,
        "lastVerifiedDaysAgo": 96,
        "freshness": "recent"
    },
    "stationScore": 80,
    "scoreBand": "excellent",
    "recommendation": "recommended",
    "routeReady": true,
    "confidence": 92,
    "confidenceBand": "high",
    "powerConfidence": "high",
    "operatorReliability": "excellent",
    "vehicleCompatibility": { "teslaCompatible": false, "ccsCompatible": true, "chademoCompatible": false, "type2Compatible": true, "j1772Compatible": false },
    "accessComplexity": "high",
    "accessReason": "Restricted access (\"garage\").",
    "tripSuitability": ["roadtrip", "fleet", "commuter"],
    "percentiles": { "powerPercentile": 71, "scorePercentile": 88, "overallPercentile": 80 },
    "whyThisStation": "Fast charging up to 62.5 kW; reported operational; recently verified; 6 charging points.",
    "summary": "ChargePoint - Manhattan West Parking in New York: 62.5 kW fast charging, recommended, 2.4 Miles away."
}
```

And the summary record that follows the stations:

```json
{
    "recordType": "summary",
    "schemaVersion": "2.5.0",
    "stationCount": 38,
    "tierDistribution": { "rapid": 6, "fast": 14, "standard": 15, "slow": 1, "unknown": 2 },
    "operationalRatio": 0.92,
    "recommendedCount": 18,
    "routeReadyCount": 17,
    "highConfidenceStations": 21,
    "singlePointOnlyCount": 5,
    "fastestStation": { "stationId": 201144, "title": "Electrify America - Hudson Yards", "maxPowerKW": 350 },
    "bestStation": { "stationId": 201144, "title": "Electrify America - Hudson Yards", "stationScore": 95 },
    "nearestRouteReadyStation": { "stationId": 148231, "title": "ChargePoint - Manhattan West Parking", "distance": 2.41 },
    "operatorInsights": [
        { "rank": 1, "operator": "ChargePoint", "operatorStationCount": 14, "avgPowerKW": 62.5, "avgStationScore": 78, "operatorScore": 78, "operatorReliability": "excellent", "operatorCoverage": "high" }
    ],
    "bestOperator": { "operator": "ChargePoint", "operatorScore": 78 },
    "operatorDiversity": "high",
    "concentration": { "topOperatorShare": 0.37, "hhi": 1840, "concentrationRisk": "medium", "note": "Charging is spread across operators (top operator 37%)." },
    "evReadinessScore": 74,
    "resilienceIndex": 68,
    "opportunityScore": 32,
    "investmentPotential": "low",
    "opportunityCount": 0,
    "candidateSiteCount": 0,
    "growth": null,
    "catchment": { "catchmentRadiusKm": 5, "overlap": 0.74, "coverageEfficiency": 26, "redundantStations": 28 },
    "fragilityIndex": 11,
    "analysisMode": "coverage",
    "infrastructureProfile": { "archetype": "mature-balanced", "expansionPressure": "low", "label": "Mature, balanced network (ready, resilient, low fragility)", "drivers": ["Strong readiness, resilient, low fragility."] },
    "benchmark": { "evReadinessPercentile": 84, "betterThanPct": 84, "sampleSize": 132, "population": "areas analysed on this account" },
    "coverageGrade": "A",
    "areaVerdict": "excellent-coverage",
    "coverageGap": false,
    "gapReason": null,
    "siteOpportunity": { "level": "none", "reasons": ["Area is already well served — limited infrastructure gap."] },
    "multiRadiusCoverage": [
        { "radiusKm": 5, "stationCount": 11, "fastChargers": 6, "coverageGrade": "A" },
        { "radiusKm": 10, "stationCount": 23, "fastChargers": 14, "coverageGrade": "A" },
        { "radiusKm": 25, "stationCount": 38, "fastChargers": 20, "coverageGrade": "A" }
    ],
    "chargingClusters": 4,
    "clusters": [ { "clusterId": 1, "size": 12, "centerLatitude": 40.7521, "centerLongitude": -73.998, "clusterType": "high-density", "rapidOrFast": 8 } ],
    "marketMaturity": "advanced",
    "routeViability": "excellent",
    "areaMetrics": { "searchAreaSqKm": 1963.5, "stationsPer100SqKm": 1.9, "fastChargersPer100SqKm": 1.0, "routeReadyDensity": 0.9 },
    "recommendations": [
        "EV-readiness 74/100 (grade A). Excellent charging coverage in this area.",
        "17 stations are route-ready (fast, operational, verified).",
        "5 stations have a single charging point — no fallback if it is occupied or out of service."
    ],
    "summary": "38 EV charging stations (EV-readiness 74/100, grade A) -- 6 rapid, 14 fast, 18 recommended, 21 high-confidence. Excellent charging coverage in this area.",
    "extractedAt": "2026-02-19T14:22:33.000Z"
}
```

When a charging tier is missing from the searched area, the actor also emits a mappable `recordType: "coverage-gap"` record (centre coordinates, radius, missing infrastructure, severity) that site-selection and GIS workflows can plot directly. Set `resolveReferenceData: true` to additionally emit a `recordType: "reference-data"` record listing every operator, connector, level, and status with its numeric ID, so you never have to memorise that 33 = CCS Type 2. You can also pass `operatorName: "Tesla"` instead of `operatorId` and the actor resolves the name to the ID for you.

#### Route-corridor analysis (opt-in)

Supply `startLatitude`, `startLongitude`, `endLatitude`, and `endLongitude` and the actor adds a `recordType: "route-analysis"` record. It samples waypoints along the great-circle line between start and end (one extra Open Charge Map query per waypoint, capped at 30), checks for route-ready chargers at each, and reports whether the journey is charge-ready and where the gaps are. This is a deterministic heuristic parameterised by `routeMaxGapKm` -- it is not a turn-by-turn routing engine.

```json
{
    "recordType": "route-analysis",
    "schemaVersion": "2.5.0",
    "corridorName": "London-Birmingham",
    "totalDistanceKm": 412.6,
    "waypointsSampled": 9,
    "sampleSpacingKm": 50,
    "maxGapAllowedKm": 120,
    "routeReady": true,
    "corridorReadiness": 88,
    "recommendedStops": 3,
    "recommendedSites": 0,
    "maxGapKm": 88.4,
    "weakSegments": 1,
    "criticalSegments": 0,
    "uniqueRouteReadyStations": 22,
    "gaps": [ { "fromKm": 152.1, "toKm": 240.5, "gapKm": 88.4, "severity": "weak" } ],
    "summary": "Corridor \"London-Birmingham\" is charge-ready over 413 km (readiness 88/100): 22 route-ready chargers, longest gap 88.4 km (under the 120 km limit), ~3 stop(s) recommended."
}
```

#### Scenario simulation + critical nodes

Pass `simulate` to model an infrastructure change. The actor recomputes EV-readiness and resilience over the perturbed station set and emits a `recordType: "simulation"` record per scenario (estimates, not forecasts). In route mode it also emits `recordType: "critical-node"` records for the single stations a corridor depends on.

```json
{
    "recordType": "simulation",
    "scenario": "Remove operator \"Tesla\"",
    "evReadinessBefore": 74,
    "evReadinessAfter": 41,
    "evReadinessChange": -33,
    "resilienceBefore": 68,
    "resilienceAfter": 52,
    "coverageLossPct": 44,
    "stationsAffected": 9,
    "summary": "Remove operator \"Tesla\": EV-readiness 74 → 41 (-33), resilience 68 → 52, 44% route-ready coverage lost.",
    "caveats": ["Directional estimate from supply changes only — not a demand or traffic forecast."]
}
```

```json
{
    "recordType": "critical-node",
    "stationId": 148231,
    "title": "Gridserve - Watford Gap",
    "latitude": 52.18,
    "longitude": -1.12,
    "dependencyScore": 100,
    "reason": "Sole route-ready charger across 2 corridor segment(s) — losing it would re-open a charging gap."
}
```

#### Dashboard + GIS records (infrastructure-twin, heat-zone)

Every run emits one compact `recordType: "infrastructure-twin"` (the whole network in one dashboard-ready row) and a set of `recordType: "heat-zone"` records (`{ latitude, longitude, radiusKm, score, zoneType }`) you can plot directly in Kepler, Mapbox, or ArcGIS.

```json
{
    "recordType": "infrastructure-twin",
    "archetype": "mature-balanced",
    "evReadinessScore": 74,
    "resilienceIndex": 68,
    "fragilityIndex": 11,
    "opportunityScore": 32,
    "coverageZones": 4,
    "criticalNodes": 0,
    "opportunityZones": 1,
    "candidateSites": 0,
    "dominantOperator": "ChargePoint",
    "concentrationRisk": "medium",
    "summary": "Mature, balanced network (ready, resilient, low fragility). EV-readiness 74/100, resilience 68, fragility 11, 4 cluster(s), 0 critical node(s)."
}
```

```json
{ "recordType": "heat-zone", "zoneType": "opportunity", "latitude": 51.21, "longitude": -0.41, "radiusKm": 15, "score": 64, "label": "Opportunity (rapid)" }
```

#### Infrastructure-planning records (opportunity, candidate-site, area-comparison)

When an area is under-served, the actor emits scored `recordType: "opportunity"` records; for critical route gaps it also emits `recordType: "candidate-site"` records (where a charger should go). Pass `compareAreas` and it emits one `recordType: "area-comparison"` ranking the areas. Name a `watchlistName` and the summary gains a `growth` block (new stations, EV-readiness change, and a growth trend) on the second and later runs.

```json
{
    "recordType": "opportunity",
    "opportunityId": "opp_route_206",
    "latitude": 52.182,
    "longitude": -1.214,
    "opportunityScore": 84,
    "recommendedInfrastructure": "rapid",
    "severity": "high",
    "reasoning": ["140 km charging gap along the corridor (critical).", "A rapid charger near this point would close a critical coverage gap."],
    "source": "route-gap"
}
```

```json
{
    "recordType": "candidate-site",
    "candidateId": "site_route_206",
    "latitude": 52.182,
    "longitude": -1.214,
    "siteScore": 84,
    "recommendedType": "ultra-rapid",
    "estimatedCoverageGainKm": 120,
    "basis": "Midpoint of a 140 km critical charging gap on corridor \"London-Birmingham\"."
}
```

```json
{
    "recordType": "area-comparison",
    "areasCompared": 3,
    "bestArea": "Manchester",
    "mostUnderserved": "Hull",
    "ranking": [
        { "rank": 1, "label": "Manchester", "stationCount": 41, "evReadinessScore": 81, "opportunityScore": 22, "resilienceIndex": 73, "coverageGrade": "A" }
    ],
    "summary": "Best EV-ready area: Manchester (81/100). Most underserved: Hull (build-out opportunity 64/100)."
}
```

#### Station record fields reference

The decision layer (added on top of the raw Open Charge Map data):

| Field | Type | Description |
|-------|------|-------------|
| `recordType` | String | `station` for a charging-station record, `summary` for the run-level rollup, `error` for a typed failure record (`failureType`: `invalid-input` / `blocked` / `timeout` / `parse-error` / `no-data`) |
| `rank` | Number | Position in the sorted result set (1 = top by the chosen `sortBy` axis) |
| `maxPowerKW` | Number | Highest connector power at the station, in kW |
| `chargingTier` | String | `rapid` (>=150 kW), `fast` (>=50 kW), `standard` (>=7 kW), `slow` (<7 kW), or `unknown` |
| `connectorTypes` | Array | Distinct connector type titles at the station |
| `reliability` | Object | `{ verified, operational, lastVerifiedDaysAgo, freshness }` -- freshness is `fresh` / `recent` / `aging` / `stale` / `unknown` |
| `stationScore` | Number | Deterministic 0-100 quality score: speed (0-40) + availability (0-25) + reliability (0-20) + redundancy (0-15) |
| `scoreBand` | String | `excellent` (>=75), `good` (>=55), `fair` (>=35), or `poor` |
| `recommendation` | String | `recommended`, `usable`, `caution`, `avoid`, or `planned` |
| `routeReady` | Boolean | True when fast/rapid, operational, and verified -- dependable for a journey stop |
| `confidence` | Number | Data-trust score 0-100 (verification recency + metadata completeness), distinct from `stationScore` |
| `confidenceBand` | String | `high` (>=75), `medium` (>=50), `low` (>=25), or `very-low` |
| `powerConfidence` | String | How much to trust the advertised peak power: `high` / `medium` / `low` |
| `operatorReliability` | String | Within-run quality tier of this station's operator: `excellent` / `good` / `fair` / `unproven` (null if operator unknown) |
| `vehicleCompatibility` | Object | `{ teslaCompatible, ccsCompatible, chademoCompatible, type2Compatible, j1772Compatible }` |
| `accessComplexity` | String | Friction to plug in, from access notes: `high` / `medium` / `low` |
| `accessReason` | String | Plain-English access note when complexity is medium/high (null otherwise) |
| `tripSuitability` | Array | Which trip profiles fit: `roadtrip` / `commuter` / `fleet` / `rideshare` / `destination` |
| `percentiles` | Object | `{ powerPercentile, scorePercentile, overallPercentile }` within this result set (null on single-result runs) |
| `singlePointOfFailure` | Boolean | True when the station has only one charging point -- no fallback if it is occupied or out of service |
| `clusterId` | Number | Geographic cluster the station belongs to (stations within ~2 km are grouped); null when no coordinates |
| `whyThisStation` | String | Plain-English rationale for the score and recommendation |
| `summary` | String | One-line plain-English summary of the station |

The raw Open Charge Map fields (preserved unchanged):

| Field | Type | Description |
|-------|------|-------------|
| `stationId` | Number | Unique station identifier in the Open Charge Map database |
| `title` | String | Station name or location title |
| `street` | String | Street address |
| `city` | String | City or town name |
| `state` | String | State, province, or region |
| `postcode` | String | Postal or ZIP code |
| `country` | String | Full country name |
| `countryCode` | String | ISO 2-letter country code |
| `latitude` | Number | Station GPS latitude |
| `longitude` | Number | Station GPS longitude |
| `operatorName` | String | Charging network operator name |
| `operatorWebsite` | String | Operator website URL |
| `connections` | Array | List of available connectors, each with type, level, powerKW, quantity, and currentType |
| `numberOfPoints` | Number | Total number of charging points at the station |
| `usageCost` | String | Pricing information (e.g., "$0.35/kWh", "Free") |
| `accessComments` | String | Notes about access, hours, or restrictions |
| `statusType` | String | Current operational status (e.g., "Operational", "Planned") |
| `isRecentlyVerified` | Boolean | Whether the station has been recently verified by a user |
| `dateLastVerified` | String | ISO 8601 timestamp of the last verification |
| `distance` | Number | Distance from the search center point (when coordinates are provided) |
| `distanceUnit` | String | Unit of the distance value (Miles or KM) |
| `url` | String | Direct link to the station page on Open Charge Map |
| `extractedAt` | String | ISO 8601 timestamp of when the data was extracted |

***

### Use cases

- **EV route planning** -- build route planning tools that help drivers find compatible charging stations along their journey, filtered by connector type and charging speed
- **Fleet management** -- monitor charging infrastructure availability near fleet depots and along delivery routes to optimize electric fleet operations
- **Competitive analysis** -- track which charging networks are expanding in specific regions by comparing station counts and locations over time
- **Real estate site selection** -- evaluate proximity to EV charging infrastructure when selecting commercial property, retail, or hospitality locations
- **Urban planning and policy** -- analyze charging station density and coverage gaps to inform municipal EV infrastructure investment decisions
- **Travel and tourism apps** -- integrate charging station data into travel planning applications so EV drivers can find chargers near hotels, restaurants, and attractions
- **Energy market research** -- study the distribution and growth of different charging levels and network operators across markets
- **Insurance and risk modeling** -- incorporate charging infrastructure data into vehicle usage models and risk assessments for EV-specific insurance products
- **GIS mapping and visualization** -- export station coordinates to GIS platforms for geographic analysis and heatmap generation
- **Academic research** -- study EV adoption patterns, infrastructure equity, and the relationship between charging access and electric vehicle ownership

***

### API & integrations

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run = client.actor("PMfpkCw1ysFSTcx0D").call(run_input={
    "latitude": 34.0522,
    "longitude": -118.2437,
    "distance": 10,
    "distanceUnit": "Miles",
    "maxResults": 100,
    "levelId": 3,
    "statusTypeId": 50,
    "apiKey": "YOUR_OCM_API_KEY",
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{item['title']} -- {item['operatorName']} -- {item['distance']} miles")
    for conn in item.get("connections", []):
        print(f"  {conn['type']}: {conn['powerKW']} kW")
```

#### JavaScript

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

const client = new ApifyClient({ token: "YOUR_APIFY_TOKEN" });

const run = await client.actor("PMfpkCw1ysFSTcx0D").call({
    latitude: 48.8566,
    longitude: 2.3522,
    distance: 5,
    distanceUnit: "KM",
    countryCode: "FR",
    maxResults: 200,
    apiKey: "YOUR_OCM_API_KEY",
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Found ${items.length} stations in Paris`);
items.forEach((station) => {
    console.log(`${station.title} -- ${station.statusType} -- ${station.connections.length} connectors`);
});
```

#### cURL

```bash
curl "https://api.apify.com/v2/acts/PMfpkCw1ysFSTcx0D/runs?token=YOUR_APIFY_TOKEN" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "latitude": 52.52,
    "longitude": 13.405,
    "distance": 10,
    "distanceUnit": "KM",
    "countryCode": "DE",
    "maxResults": 150,
    "apiKey": "YOUR_OCM_API_KEY"
  }'
```

#### Integration options

- **Google Sheets** -- automatically export EV station data to a spreadsheet for analysis, sharing, or dashboard creation
- **Slack / Email** -- receive notifications when new stations appear in your monitored areas
- **Webhooks** -- send results to your own API endpoint for custom processing or database ingestion
- **Zapier / Make** -- connect to thousands of other apps and automate EV charging data workflows
- **Amazon S3 / Google Cloud Storage** -- archive historical station data for trend analysis

***

### Use in Dify

Drop this actor into [Dify](https://docs.apify.com/platform/integrations/dify) workflows via the Apify plugin's Run Actor node. Every station comes back scored, classified, and recommended as structured JSON -- `chargingTier` (rapid / fast / standard / slow), `recommendation` (recommended / usable / caution / avoid / planned), and the `routeReady` boolean your downstream node branches on. A raw geocoding or POI scraper pointed at the same data returns unranked rows; this returns decisions.

- **Actor ID:** `ryanclinton/open-charge-map`
- **Sample input** (find a dependable rapid charger near a route waypoint):

```json
{
    "latitude": 51.4816,
    "longitude": -3.1791,
    "distance": 15,
    "distanceUnit": "Miles",
    "minPowerKW": 50,
    "sortBy": "score",
    "statusTypeId": 50,
    "apiKey": "YOUR_OCM_API_KEY"
}
```

- **Branching example** -- a Dify if/else node routes on the per-station decision without parsing any prose:

```
IF  recommendation == "recommended" AND routeReady == true
      -> add to the trip plan as a confirmed charging stop
ELSE IF  chargingTier == "rapid" OR chargingTier == "fast"
      -> offer as a backup fast charger (verify availability first)
ELSE IF  recommendation == "planned"
      -> note for future trips (station not yet live)
ELSE
      -> skip
```

The run-level `recordType: "summary"` record gives a Dify workflow a one-call area read to branch on too -- `areaVerdict` (`excellent-coverage` ... `no-fast-charging`), `routeReadyCount`, and `nearestRouteReadyStation` let a flow decide whether the area is worth routing through at all before iterating stations. Set `outputProfile: "minimal"` to keep the payload lean for an LLM node, and the `recommendations[]` array on the summary is plain-English text usable verbatim -- no LLM rewriting needed.

***

### How it works

One Open Charge Map query per run (plus extra queries only when you opt into route, multi-area, or reference-data modes), then a deterministic analytics pass over the response: every station is scored and classified, the area is profiled, and the planning, scenario, and GIS records are derived in memory before the dataset is written. No LLM, no external calls beyond Open Charge Map, fully reproducible. The API key is sent in the request header, transient 403/429/5xx responses retry with exponential backoff, and a handled failure exits cleanly with a typed `error` record rather than a failed run.

***

### Performance & cost

This actor is pay-per-event: you are charged **$0.001 per station record returned** (the `station-fetched` event). The run-level summary, planning, and GIS records (summary, opportunity, coverage-gap, candidate-site, critical-node, simulation, heat-zone, infrastructure-twin, area-comparison, reference-data) are derived and never charged, and no charge is made for an empty result. Apify platform compute is billed separately and is minimal (one API call per run, a few extra only in route / multi-area / reference-data modes).

| Scenario | Station records | Approx. run time | PPE charge (output events) |
|----------|-----------------|-------------------|-----------------------------|
| Small radius search (5 mi) | 50 | 5--8 seconds | $0.05 |
| Medium radius search (25 mi) | 200 | 8--12 seconds | $0.20 |
| Large radius search (50 mi) | 500 | 10--15 seconds | $0.50 |
| Filtered search (`minPowerKW: 150`) | 20 | 5--8 seconds | $0.02 |
| Dry-run mode (no API key) | 0 charged | 3--5 seconds | $0.00 |

Use `minPowerKW`, `minConfidence`, or a smaller radius to control how many station records (and therefore charges) a run produces. The Open Charge Map data API itself is free to use under its open licence.

***

### Limitations

- **Maximum 500 results per run** -- the Open Charge Map API limits a single query to 500 results. For broader coverage, run multiple searches with different center points or regions.
- **API key required for live data** -- while the actor supports a dry-run demo mode without a key, live station data requires a free API key from openchargemap.org.
- **Data accuracy depends on community contributions** -- Open Charge Map is community-maintained, so some station listings may be outdated, incomplete, or unverified. Check the `isRecentlyVerified` and `dateLastVerified` fields to assess data freshness.
- **Rate limiting** -- the Open Charge Map API may return 403 errors under heavy load. The actor retries up to 3 times with exponential backoff, but sustained high-frequency usage may require spacing out runs.
- **Operator and connector IDs are not self-documenting** -- you need to reference the Open Charge Map reference data documentation to find the numeric IDs for specific operators, connector types, and status values.
- **No real-time availability data** -- the actor returns station metadata (location, connectors, status) but does not provide real-time charger availability or occupancy information.
- **Distance sorting requires coordinates** -- if you search by country code only without providing latitude/longitude, results will not include distance values and are not sorted by proximity.

***

### Responsible use

- **Respect the Open Charge Map API terms of service** -- Open Charge Map provides its data for free under an open license. Register for your own API key and do not share it publicly or use it in ways that violate their usage policy.
- **Avoid excessive request frequency** -- while the API is free, making thousands of requests per minute can strain the service. Space out scheduled runs and use reasonable intervals (hourly at most for monitoring use cases).
- **Attribute data to Open Charge Map** -- if you publish or redistribute data obtained through this actor, credit Open Charge Map as the data source per their licensing terms.
- **Do not use for unauthorized commercial purposes** -- review the Open Charge Map data license before incorporating station data into commercial products. The data is provided under the Creative Commons Attribution-ShareAlike 4.0 license.
- **Protect your API key** -- the `apiKey` input field is marked as secret and will not be visible in run logs. Never share your API key in public repositories or documentation.

***

### FAQ

**Q: Do I need an API key to use this actor?**
**A:** A free API key from Open Charge Map is strongly recommended for live data. Without one, the actor runs in dry-run mode and returns a single sample record so you can test your integration and see the output schema. Register your key at [openchargemap.org](https://openchargemap.org) under My Profile > My Apps > Register Application.

**Q: How do I get a free Open Charge Map API key?**
**A:** Go to [openchargemap.org](https://openchargemap.org), create an account or sign in, navigate to My Profile > My Apps, click "Register an Application", fill in a name and description, and you will receive your API key immediately. It is completely free.

**Q: How many charging stations are in the Open Charge Map database?**
**A:** Open Charge Map contains over 300,000 EV charging station locations across more than 100 countries. The database is continuously updated by community contributors, charging network operators, and automated data imports.

**Q: Can I search without specifying GPS coordinates?**
**A:** Yes. If you omit latitude and longitude but provide a country code, the API returns stations from that country. However, results will not include distance values and are not sorted by proximity. For the best results, provide specific coordinates.

**Q: What are the common connector type IDs?**
**A:** The most frequently used connector type IDs are: 1 = Type 1 (J1772), 25 = Type 2 (Mennekes), 32 = CCS (Type 1), 33 = CCS (Type 2), 2 = CHAdeMO, 27 = Tesla Supercharger. The full list is available in the Open Charge Map reference data API.

**Q: What do the charging level IDs mean?**
**A:** Level 1 (ID: 1) is standard household outlet charging at up to 2 kW. Level 2 (ID: 2) is medium-speed charging at 2--40 kW, common at workplaces and public parking. Level 3 (ID: 3) is DC Fast Charging at 40 kW and above, suitable for highway travel and rapid top-ups.

**Q: How often is the Open Charge Map data updated?**
**A:** The database is updated continuously as community members submit and verify stations. Most stations in major markets have been verified within the past year. Use the `isRecentlyVerified` and `dateLastVerified` output fields to assess data freshness for each station.

**Q: What does dry-run mode return?**
**A:** When no API key is provided, the actor returns a single sample record with realistic field values and a title indicating it is demo data. This lets you test your downstream integration, verify the output schema, and confirm that your Apify workflow is set up correctly before obtaining an API key.

**Q: Can I get more than 500 results?**
**A:** Not in a single run -- the Open Charge Map API limits responses to 500 results per query. To cover a larger area, run multiple searches with different center coordinates or split your search into smaller geographic regions.

**Q: Does this actor provide real-time charger availability?**
**A:** No. The actor returns station metadata including location, connectors, power output, operator, and verification status. Real-time availability (whether a specific plug is currently in use) is not part of the Open Charge Map API.

**Q: How do I find the operator ID for a specific network?**
**A:** You can look up operator IDs in the Open Charge Map reference data API at `https://api.openchargemap.io/v3/referencedata`. Some common operator IDs include 23 for Tesla and 5 for ChargePoint, but these may change -- always verify against the reference data.

**Q: Can I schedule this actor to run automatically?**
**A:** Yes. On the Apify platform, you can set up scheduled runs at any interval -- hourly, daily, weekly, or on a custom cron schedule. This is useful for monitoring new station installations or tracking changes in a specific region over time.

***

### Related actors

| Actor | Description |
|-------|-------------|
| [Nominatim Geocoder](https://apify.com/ryanclinton/nominatim-geocoder) | Convert street addresses to latitude/longitude coordinates for use as input to this actor |
| [OpenStreetMap POI Search](https://apify.com/ryanclinton/osm-poi-search) | Search for points of interest on OpenStreetMap including parking lots and amenities near charging stations |
| [REST Countries Data Search](https://apify.com/ryanclinton/rest-countries-search) | Look up ISO country codes, population data, and geographic info to complement charging station analysis |
| [Website Change Monitor](https://apify.com/ryanclinton/website-change-monitor) | Monitor charging network operator websites for pricing changes, new station announcements, or policy updates |
| [IP Geolocation Lookup](https://apify.com/ryanclinton/ip-geolocation-lookup) | Resolve IP addresses to geographic coordinates for location-aware charging station searches |

# Changelog

This Actor's version history is a separate document: https://apify.com/ryanclinton/open-charge-map/changelog.md

# Actor input Schema

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

Search center latitude (e.g., 40.7128 for New York City).

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

Search center longitude (e.g., -74.006 for New York City).

## `distance` (type: `number`):

Search radius from the center point.

## `distanceUnit` (type: `string`):

Unit for the search radius.

## `countryCode` (type: `string`):

2-letter ISO country code to filter results (e.g., 'US', 'GB', 'DE'). Leave empty for all countries.

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

Maximum number of stations to return (1-500).

## `operatorId` (type: `number`):

Filter by charging network operator ID (e.g., 23 for Tesla). Tip: use Operator Name instead if you do not know the ID.

## `operatorName` (type: `string`):

Filter by operator name instead of ID (e.g., 'Tesla', 'ChargePoint'). The actor looks the name up in Open Charge Map's reference data and resolves it to the operator ID. Exact match preferred, falls back to a partial match.

## `connectionTypeId` (type: `number`):

Filter by connector type ID (e.g., 1=Type 1, 25=Type 2, 32=CCS, 27=Tesla Supercharger).

## `levelId` (type: `number`):

Filter by charging level (1=Level 1, 2=Level 2, 3=DC Fast Charging).

## `statusTypeId` (type: `number`):

Filter by station status (50=Operational, 100=Not Operational, 150=Planned).

## `apiKey` (type: `string`):

Required. Register a free API key at openchargemap.org (sign in, then My Profile > My Apps > Register Application).

## `minPowerKW` (type: `integer`):

Only return stations whose fastest connector is at least this many kW. Leave empty to return all. Stations with no published power are excluded when this is set. Example: 50 for fast/rapid only, 150 for ultra-rapid only.

## `minConfidence` (type: `integer`):

Only return stations whose data-trust confidence score (0-100) is at least this value. Confidence reflects verification recency and metadata completeness (distinct from the quality score). Use 70-80 to exclude stale or sparse listings.

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

Order of the returned stations. 'distance' (default) sorts nearest first, 'power' sorts fastest first, 'score' sorts by overall station quality, 'confidence' sorts by data-trust confidence.

## `outputProfile` (type: `string`):

How much detail per station record. 'full' (default) includes the raw connections array and all fields; 'standard' drops the verbose connections/access detail but keeps every decision field; 'minimal' returns only the core location + decision fields for lightweight automation.

## `resolveReferenceData` (type: `boolean`):

When true, the actor emits one 'reference-data' record listing every operator, connector type, charging level, and status type with its ID and title — so you can look up the numeric IDs the other filters expect instead of memorising them.

## `startLatitude` (type: `number`):

Optional. Provide all four route coordinates to enable route-corridor analysis: the actor samples waypoints along the start-to-end line, queries chargers around each, and reports route readiness and charging gaps. Each waypoint is an extra OCM query.

## `startLongitude` (type: `number`):

Longitude of the route start point. Required (with the other three) to enable route-corridor analysis.

## `endLatitude` (type: `number`):

Latitude of the route end point. Required (with the other three) to enable route-corridor analysis.

## `endLongitude` (type: `number`):

Longitude of the route end point. Required (with the other three) to enable route-corridor analysis.

## `routeMaxGapKm` (type: `integer`):

Route mode only. The longest stretch (km) without a route-ready charger you consider acceptable. A gap longer than this is flagged 'critical' and marks the route not charge-ready; longer than half this is 'weak'. Default 120.

## `routeSampleKm` (type: `integer`):

Route mode only. Distance between sampled waypoints along the route (km). Smaller spacing is more accurate but makes more OCM queries. Capped at 30 waypoints total. Default 50.

## `corridorName` (type: `string`):

Route mode only. Optional label for the corridor (e.g. 'London-Birmingham') used in the route-analysis record. Defaults to the start/end coordinates.

## `compareAreas` (type: `array`):

Optional. Provide 2-8 areas to rank them by EV-readiness and build-out opportunity for site selection. Each area is an object: { "label": "City A", "latitude": 51.5, "longitude": -0.12, "distance": 10 }. One extra OCM query per area. The actor emits an 'area-comparison' record with the ranking.

## `watchlistName` (type: `string`):

Optional. Name a watchlist to track infrastructure growth across scheduled runs. The actor stores a snapshot per watchlist and reports new stations, new rapid chargers, EV-readiness change, and a growth trend since the last run. First run on a watchlist establishes the baseline.

## `analysisMode` (type: `string`):

Frame the run around a job. 'coverage' (can EVs charge here?), 'planning' (where should chargers be built?), 'route' (can I drive through here?), 'investment' (where is the build-out opportunity?), 'competition' (which operators dominate?), 'benchmark' (how do areas compare?). Tunes the default sort. Auto-resolved from your input when left blank.

## `simulate` (type: `object`):

Optional what-if modelling, recomputed deterministically over the result set. Provide any of: { "removeOperator": "Tesla" } (what if a network failed), { "removeTopPercent": 10 } (network fragility), { "addRapidChargers": 5 } (directional gain from new rapid chargers). Emits a 'simulation' record per scenario with before/after EV-readiness and resilience. Estimates only, not forecasts.

## Actor input object example

```json
{
  "latitude": 40.7128,
  "longitude": -74.006,
  "distance": 10,
  "distanceUnit": "Miles",
  "maxResults": 50,
  "sortBy": "distance",
  "outputProfile": "full",
  "resolveReferenceData": false,
  "routeMaxGapKm": 120,
  "routeSampleKm": 50
}
```

# Actor output Schema

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

No description

# 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 = {
    "latitude": 40.7128,
    "longitude": -74.006,
    "distance": 10,
    "distanceUnit": "Miles",
    "maxResults": 50,
    "sortBy": "distance",
    "outputProfile": "full",
    "routeMaxGapKm": 120,
    "routeSampleKm": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("ryanclinton/open-charge-map").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 = {
    "latitude": 40.7128,
    "longitude": -74.006,
    "distance": 10,
    "distanceUnit": "Miles",
    "maxResults": 50,
    "sortBy": "distance",
    "outputProfile": "full",
    "routeMaxGapKm": 120,
    "routeSampleKm": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("ryanclinton/open-charge-map").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 '{
  "latitude": 40.7128,
  "longitude": -74.006,
  "distance": 10,
  "distanceUnit": "Miles",
  "maxResults": 50,
  "sortBy": "distance",
  "outputProfile": "full",
  "routeMaxGapKm": 120,
  "routeSampleKm": 50
}' |
apify call ryanclinton/open-charge-map --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ryanclinton/open-charge-map"
        }
    }
}
```

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/PMfpkCw1ysFSTcx0D/builds/p3SSgql6lHAX4M331/openapi.json
