# AU Mobile Coverage — phone signal: Telstra, Optus, Vodafone/TPG (`davidar/au-mobile-coverage`) Actor

Carrier-predicted outdoor mobile coverage in Australia (ACMA 2026 grades: Good / Moderate / Basic / No Coverage) for Telstra, Optus and TPG/Vodafone, 4G and 5G (TPG with dBm), at coordinates or resampled along a route — with a per-carrier summary of where the phones drop out.

- **URL**: https://apify.com/davidar/au-mobile-coverage.md
- **Developed by:** [David Roberts](https://apify.com/davidar) (community)
- **Categories:** Travel, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 coverage points

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

## AU Mobile Coverage — phone signal checker for Telstra, Optus and Vodafone/TPG 4G/5G, at an address or along a road trip

Will my phone work here, and which carrier is best? Grade any Australian coordinates — a house, a campsite, a fleet depot, or a whole road trip resampled every few kilometres (give it `"origin": "Brisbane QLD", "destination": "Melbourne VIC"` and it routes the drive for you) — against the carriers' own predicted-coverage models, the same data behind their 4G and 5G coverage maps. One row per point with Telstra, Optus and TPG/Vodafone 4G / 5G grades (TPG also gives predicted dBm), plus a run summary that says how many kilometres of your route are Good, Moderate, Basic or No Coverage on each network and exactly where the weak and dead stretches are: the mobile black spots and no-signal dead zones on your road.

The grades are the ones the carriers publish under the **ACMA Mobile Network Coverage Maps Industry Standard 2026**: every Australian mobile network operator must map 4G and 5G on a common predictive model with four grades — **Good / Moderate / Basic / No Coverage** — at 100 m resolution, outdoor at ground level, refreshed at least quarterly. That makes the vocabulary identical across carriers and stable enough to build on. This Actor reads the carriers' public coverage checkers (Telstra's and TPG's point lookups, Optus's map tiles); it does not measure anything itself.

### What you get

| Field                                                                                 | Meaning                                                                                                                                                                                                                                                                              |
| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `carriers.telstra.data['4G']`, `['5G']`                                               | Telstra retail network (Telstra, Boost). `5G` is the better of `5G_NSA` (non-standalone, what most handsets use) and `5G_SA` (standalone).                                                                                                                                           |
| `carriers.optus.data['4G']`, `['5G']`, `['5G_NSA']`, `['5G_SA']`                      | Optus network (Optus, amaysim, Coles Mobile, Moose, Southern Phone…).                                                                                                                                                                                                                |
| `carriers.tpg.data['4G']`, `['5G']`, `['5G_NSA']`, `['5G_SA']`, `dbm`, `responseType` | TPG Telecom / Vodafone network (Vodafone, TPG, iiNet, Kogan, Lebara, felix, Swoop…). The only carrier that publishes the **predicted signal strength in dBm** per technology. `5G_SA` is the N-band (standalone-capable) grade, `5G_NSA` the X-band grade MVNO plans are limited to. |
| `carriers.telstra_wholesale.data`                                                     | Optional. Telstra's wholesale (MVNO) footprint — Aldi, Belong, Woolworths, Tangerine, More, Exetel… — which is smaller than retail. No NSA/SA split.                                                                                                                                 |
| `best['4G']`, `best['5G']`                                                            | Best grade across the requested carriers and which carriers achieve it — "will *any* phone work here".                                                                                                                                                                               |
| `point.routeKm`                                                                       | Route samples only: distance along the route.                                                                                                                                                                                                                                        |
| `status`                                                                              | `ok` = every requested carrier answered; `partial` = at least one carrier `unknown`; `unknown` = none answered (not charged).                                                                                                                                                        |

Every carrier block carries `status`, `source` (name, URL, attribution, model vintage), `retrievedAt` and, on failure, `error`. **`No Coverage` is a real answer from the carrier's model. `unknown` is a fetch or decode failure and must never be read as "no coverage".**

The run summary is written to the key-value store as `OUTPUT` (and the Console status line): per carrier and for the cross-carrier best, grade counts, route kilometres per grade, and `weak4G` / `dead4G` stretches (consecutive samples graded Basic-or-worse / No Coverage) with start/end km and coordinates. When both `telstra` and `telstra_wholesale` are requested, `telstraWholesale.differsFromRetail` lists the points where the MVNO footprint is graded lower than retail on 4G or 5G — the "Aldi versus Boost" question, answered per run. On a 1,700 km inland route in Sep 2026 they did not differ at all.

#### Sample row

```json
{
    "input": { "id": "pilliga", "index": 2, "kind": "point" },
    "point": { "lat": -30.6135, "lng": 149.5766 },
    "status": "ok",
    "carriers": {
        "telstra": {
            "status": "ok",
            "data": { "4G": "Basic", "5G": "Basic", "5G_NSA": "No Coverage", "5G_SA": "Basic", "product": "retail" },
            "source": {
                "id": "telstra.coverage.retail",
                "name": "Telstra mobile coverage map (retail network) — ACMA-standard prediction",
                "url": "https://www.telstra.com.au/coverage-networks/our-coverage",
                "licence": "unofficial endpoint; Telstra website terms apply",
                "attribution": "Coverage grades © Telstra Corporation Limited"
            },
            "retrievedAt": "2026-09-11T09:20:11.412Z",
            "durationMs": 231
        },
        "optus": {
            "status": "ok",
            "data": {
                "4G": "Basic",
                "5G": "No Coverage",
                "5G_NSA": "No Coverage",
                "5G_SA": "No Coverage",
                "layerVersion": "v079"
            },
            "source": {
                "id": "optus.coverage",
                "name": "Optus mobile coverage map (SpatialBuzz tiles) — ACMA-standard prediction",
                "url": "https://www.optus.com.au/living-network/coverage",
                "licence": "unofficial endpoint; Optus website terms apply",
                "attribution": "Coverage grades © Singtel Optus Pty Limited",
                "vintage": "model updated 24/08/2026, layer set v079"
            },
            "retrievedAt": "2026-09-11T09:20:11.398Z",
            "durationMs": 188
        }
    },
    "best": {
        "4G": { "grade": "Basic", "carriers": ["telstra", "optus"] },
        "5G": { "grade": "Basic", "carriers": ["telstra"] }
    },
    "note": "Carrier-predicted outdoor ground-level coverage under the ACMA Mobile Network Coverage Maps Industry Standard 2026 (100 m grid, reviewed at least quarterly). Not a measurement; does not apply indoors or inside a vehicle. Unofficial endpoints.",
    "meta": { "retrievedAt": "2026-09-11T09:20:11.412Z", "durationMs": 240 }
}
```

#### Sample OUTPUT summary (route)

```json
{
    "points": 61,
    "routePoints": 61,
    "routeKm": 1494.9,
    "stepKm": 25,
    "carriers": {
        "telstra": {
            "points": {
                "4G": { "Good": 21, "Moderate": 21, "Basic": 14, "No Coverage": 4, "unknown": 0 },
                "5G": { "…": "…" }
            },
            "routeKm": {
                "4G": { "Good": 519.9, "Moderate": 525, "Basic": 350, "No Coverage": 100, "unknown": 0 },
                "5G": { "…": "…" }
            },
            "weak4G": [
                {
                    "fromKm": 250,
                    "toKm": 300,
                    "km": 50,
                    "from": { "lat": -28.43, "lng": 150.98 },
                    "to": { "lat": -28.55, "lng": 150.31 },
                    "points": 2,
                    "worst": "No Coverage"
                }
            ],
            "dead4G": [{ "fromKm": 250, "toKm": 275, "km": 25, "…": "…" }]
        },
        "optus": { "…": "…" }
    },
    "best": { "…": "same shape, best of the requested carriers at each sample" }
}
```

#### GeoJSON output

The same result, as geometry: an [RFC 7946](https://datatracker.ietf.org/doc/html/rfc7946) `FeatureCollection` in the key-value record `GEOJSON` (its own record because a long route at a small step is thousands of features; `OUTPUT.geojson` = `{ "record": "GEOJSON", "features": N }`). It is for rendering your own map — Leaflet, MapLibre, QGIS, geojson.io, a notebook, or an agent with a plotting tool loads it in one step. This Actor returns data, not images: you pick the style, colours and basemap.

- **Route**: one `LineString` per consecutive pair of samples, graded as the sample it starts at (the same `[fromKm, toKm)` convention as `routeKm` and the stretches). Properties: `fromKm`, `toKm`, `km`, `<carrier>4G` / `<carrier>5G` for each requested carrier (`telstra4G`, `optus5G`, `telstra_wholesale4G`…), `best4G`, `best5G`, `dead4G` (`true` if any requested carrier is No Coverage on 4G), `worst4G`.
- **Points**: one `Point` per point-mode row with `index`, `id` (echoed), per-carrier grades, `best4G`, `best5G`.
- Positions are `[lng, lat]`. An unknown grade is `null` — draw it as "no data", never as No Coverage.
- It is a straight segment between samples, not the road geometry between them; for a smoother line use a smaller `stepKm`.

```json
{
    "type": "Feature",
    "geometry": {
        "type": "LineString",
        "coordinates": [
            [143.978, -38.54],
            [143.8, -38.6]
        ]
    },
    "properties": {
        "kind": "route",
        "index": 5,
        "fromKm": 45.2,
        "toKm": 60,
        "km": 14.8,
        "telstra4G": "Basic",
        "telstra5G": "No Coverage",
        "optus4G": "No Coverage",
        "optus5G": "No Coverage",
        "best4G": "Basic",
        "best5G": "No Coverage",
        "dead4G": true,
        "worst4G": "No Coverage"
    }
}
```

### Use cases

- **Mobile reception at an address** before you rent, buy or move: which carrier has Good 4G or 5G at the house, and which only Basic.
- **Which carrier is best along this road**: kilometres of Good / Moderate / Basic / No Coverage per network for a whole drive, in one run.
- **Road trip and outback planning**: where the phone signal drops out, how long each dead zone lasts, and whether *any* network covers it (`best`).
- **Mobile black spots on a regular route**: a freight run, a school bus route or a farm road, re-checked after each quarterly model refresh.
- **Campsite and caravan park reception**: grade a list of campgrounds or free camps as `points` and keep the ones with 4G.
- **Remote-area work sites and fleet depots**: which SIM to issue for a crew or a vehicle tracker that has to stay connected.
- **Boost or ALDI Mobile?** Both resell Telstra, but Boost gets the retail network and ALDI, Belong, Woolworths and other MVNOs the smaller wholesale footprint; request `telstra_wholesale` to grade both, point by point.
- **Vodafone/TPG signal strength in dBm**: the only carrier that publishes a predicted number, not just a grade.
- **Coverage map data for your own app or dashboard**: GeoJSON segments coloured by grade, no screen-scraping of four different coverage checkers.
- **Agents answering "will I have signal at X?"**: one call returns all carriers under the same ACMA grades.

### Input

| Field               | Type   | Notes                                                                                                                                       |
| ------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `points`            | array  | `{ "lat", "lng", "id"? }` objects (`lon`, `latitude`/`longitude` also accepted), or `{ "address", "id"? }` to have the address geocoded.    |
| `addresses`         | array  | Street addresses or place names, one per line, geocoded for you (paid plans; $0.001 each on the routing actor). See Addresses.              |
| `origin`            | string | Start of a route to be computed for you: a place name or address (`"Brisbane QLD"`) or `"lat,lng"`. Needs `destination`. See Route by name. |
| `destination`       | string | End of that route, same forms.                                                                                                              |
| `waypoints`         | array  | Optional stops in between, in order: place names or `"lat,lng"` strings, same forms as `origin`. Up to 18. See Why waypoints.               |
| `profile`           | string | Travel mode for origin/destination: `car` (default), `bike`, `foot`, `truck`, `motorcycle`, `scooter`, `bus`, `taxi`.                       |
| `polyline`          | string | Encoded polyline of a route — Google Directions `overview_polyline.points`, OSRM, Mapbox, Valhalla. Wins over `coordinates` and `origin`.   |
| `polylinePrecision` | 5 | 6 | 5 for Google and OSRM's default, 6 for Mapbox / Valhalla / OSRM `polyline6`. Default 5.                                                     |
| `coordinates`       | array  | Alternative to `polyline`: `[lat, lng]` pairs, latitude first like everywhere else. Wins over `origin`.                                     |
| `stepKm`            | number | Route sample spacing, default 5. The models are 100 m grids; 5 km catches town/scrub transitions on a highway, 1 km is thorough.            |
| `carriers`          | array  | Any of `telstra`, `optus`, `tpg`, `telstra_wholesale`. Default `[\"telstra\", \"optus\", \"tpg\"]`.                                         |
| `concurrency`       | 1–8    | Default 4. Requests per carrier host are capped independently of this (see Politeness).                                                     |

`points` and a route can be combined; point rows come first, then route samples in order with `routeKm`. The easiest route input is `origin` + `destination` (see below). If you bring your own route, **pass the directions polyline, not your own resampled points**: a coordinate list is treated as the route geometry, so coarse samples are joined by straight lines and the route comes out shorter than the road (and the samples land off it). Up to **5000 points per run** including route samples — raise `stepKm` or split the route if you hit it. Coordinates outside Australia are skipped with a warning (points) or rejected (route vertices). If you already have directions from another API, pass its polyline; otherwise give `origin` and `destination`.

```json
{
    "points": [{ "id": "melbourne-flinders-st", "lat": -37.8183, "lng": 144.9671 }],
    "polyline": "…overview_polyline from Google Directions…",
    "stepKm": 5,
    "carriers": ["telstra", "optus", "tpg"]
}
```

#### Route by name

```json
{ "origin": "Brisbane QLD", "destination": "Melbourne VIC", "stepKm": 5 }
```

With `origin` and `destination` (and optional `waypoints` and `profile`), the Actor asks the **Directions, Routing & Distance Matrix API actor ([davidar/openstreetmap-directions-api](https://apify.com/davidar/openstreetmap-directions-api))** for the route, then samples it every `stepKm` exactly as if you had passed its polyline. Place names are geocoded within Australia; a town name resolves to the town centre, which is fine for a drive between towns. Use `"lat,lng"` (for example `"-27.4648,153.019"`) when the exact start matters.

**Why waypoints.** The router takes the shortest road, not the one you will drive, and route choice moves the answer more than the checker does. Goondiwindi → Dubbo unrouted leaves the Newell Highway at Coonabarabran for the Mendooran back road, which has about 30 km with no Telstra coverage; if you are driving the Newell via Gilgandra, say so with `"waypoints": ["Gilgandra NSW"]` and grade that road instead. Waypoints take the same forms as `origin` and `destination` — place names or `"lat,lng"` strings — up to 18.

**What it costs.** The routing actor runs under your account, so its charges appear on *that* actor in your Apify billing, not on this one: one `route_computed` ($0.003), one `geocoded_location` ($0.001) per place name (two for the example above — coordinates are free) and Apify's standard actor-start event for a 512 MB run. This Actor charges `coverage_point` per sample as before and adds no event of its own. Brisbane → Melbourne by name at 5 km is about $0.005 of routing plus ~340 samples.

**Free Apify plans** get the routing actor's community-router tier: **coordinates only, car only** — place names, `addresses` and other profiles come back unsupported. Pass `"lat,lng"` origins and destinations, coordinates in `points`, or a polyline.

**Addresses.** `addresses` (strings) and `points` given as `{"address": "12 Smith St, Fitzroy VIC 3065", "id": "smith-st"}` are geocoded through the same routing actor in one nested run — one `geocoded_location` ($0.001) per address that resolves, billed on that actor, nothing for one that doesn't — and then graded exactly like coordinate points. The row keeps what you sent in `input.address` and what the geocoder matched in `input.label`; check the label when the address was vague. The routing actor's word-match rule applies, so a bare street name can't resolve to a shop in another state: an address that cannot be placed is listed in `OUTPUT.geocoding.failed` with the reason, is not graded and is not charged. Up to 1000 addresses per run. Forms that resolve well: a full street address with suburb and postcode (`12 Smith St, Fitzroy VIC 3065`), a town (`Coonabarabran NSW`), or a landmark name on its own (`Flinders Street Station`). A landmark followed by a comma and the city (`Flinders Street Station, Melbourne VIC`) makes the geocoder read the city as the place and can fail — drop the comma or the city.

**If the route can't be found** (a place name that matches nothing, no road between the points, the routing service down), the run stops before grading anything, charges nothing here, and the status message says why. The routing actor may still charge for place names it resolved before the route failed ($0.001 each) and its start event; see [its pricing](https://apify.com/davidar/openstreetmap-directions-api). `OUTPUT` then holds only `route: { actor, runId, error }` and `warnings`, so you can trace the routing run:

```
route lookup failed: geocode_failed: no match for "Nowhereville" — pass a polyline or coordinates instead
```

**Too many samples.** The 5000-point cap is checked before the routing actor is called when every location is `"lat,lng"` (straight-line distance × 1.2); with place names it can only be checked on the routed line, and then the run fails with the route's length and the smallest `stepKm` that fits — the route is computed and billed on the routing actor, so pick `stepKm` from the drive's length (1,700 km at 0.5 km is ~3,400 samples).

**Spending limit.** The routing run is a separate run with its own charge cap ($0.10, or this run's spending limit if lower); what it charges (about $0.025 with 20 place names) is not counted against this run's *Maximum cost per run*.

**Scoped API tokens.** If you run this Actor with a scoped API token in Restricted mode, give it Run permission on `davidar/openstreetmap-directions-api` and access to default run storages, or pass a polyline.

**Precedence.** `polyline` wins over `coordinates`, which wins over `origin`/`destination`; the ignored input is named in a warning. A `coordinates` list with no valid pair doesn't count, so `origin`/`destination` are used. `points` combine with any of them.

The run summary in `OUTPUT` gains a `route` block when the route was computed for you:

```json
{
    "route": {
        "actor": "davidar/openstreetmap-directions-api",
        "runId": "…",
        "profile": "car",
        "distanceKm": 1719.4,
        "durationMin": 1078.2,
        "locations": [
            { "query": "Brisbane QLD", "label": "Brisbane, QLD, Australia", "lat": -27.4648, "lng": 153.019 },
            { "query": "Melbourne VIC", "label": "Melbourne, VIC, Australia", "lat": -37.8183, "lng": 144.9671 }
        ],
        "warnings": []
    }
}
```

`distanceKm` / `durationMin` are the routing engine's figures for the whole drive (`routeKm` in the summary is the same road, measured along the decoded geometry). `locations` echoes each input with what a place name matched — check `label` before trusting a long route. `warnings` relays the routing row's warnings. `route` is absent when you passed a polyline or coordinates.

### Coverage of carriers

| Network           | Retail brands it answers for                                   | Source                                                 | 4G  | 5G NSA / SA      |
| ----------------- | -------------------------------------------------------------- | ------------------------------------------------------ | --- | ---------------- |
| Telstra           | Telstra, Boost                                                 | Telstra coverage checker (point lookup)                | ✅  | ✅ / ✅          |
| Telstra wholesale | Aldi, Belong, Woolworths, Tangerine, More, Exetel, Lebara…     | Telstra coverage checker, `wholesale` product          | ✅  | combined 5G only |
| Optus             | Optus, amaysim, Coles, Moose, Southern Phone, Dodo, iPrimus…   | Optus coverage map tiles                               | ✅  | ✅ / ✅          |
| TPG / Vodafone    | Vodafone, TPG, iiNet, felix, Kogan, Lebara, Swoop, Moose, Lyca | TPG/Vodafone coverage checker (point lookup, with dBm) | ✅  | ✅ / ✅          |

TPG's published map is the union of its own network and the regional Optus network it shares (MOCN), so regionally a TPG grade often matches Optus's; in metro areas it is TPG's own footprint.

### Reading the grades

The ACMA standard's own descriptions: **Good** — high-quality experience with seamless connectivity; **Moderate** — generally reliable, some variability; **Basic** — connectivity may be limited or intermittent (calls and texts, data may struggle); **No Coverage** — predicted signal below −115 dBm.

Things the standard itself says, which apply to every row here:

- **Outdoor, ground level.** Indoor and in-vehicle coverage is not modelled and is generally worse. A "Basic" grade on a highway is what you get standing beside the car with the phone held up, not on a call through the windscreen.
- **A prediction, not a measurement.** Terrain, foliage, buildings and handset quality all move the real result. Treat Basic-or-worse stretches as "plan for no signal".
- **Grid is 100 m.** Points are graded on the cell they fall in; two rows 50 m apart can differ.
- **Refreshed quarterly.** Optus's `source.vintage` carries the model date its map reports; Telstra's checker does not expose one.

Also: `5G` is "any 5G". A site with `5G_SA` only (Telstra flags these `coverage5GSAOnly`) needs a standalone-capable handset and plan; `5G_NSA` is the common case. Telstra's own checker headline is the NSA grade — this Actor reports the better of the two and gives you both.

TPG's `dbm` values sit on the ACMA thresholds the checker returns alongside them: Good ≥ −95 dBm, Moderate ≥ −105, Basic ≥ −115, No Coverage below. Two "Good" points at −70 and −94 dBm are the same grade and a world apart in practice — the number is worth keeping.

### Politeness and reliability

All three sources are the carriers' public, unauthenticated coverage checkers — not documented APIs. The Actor keeps at most 2 requests in flight to each of Telstra and TPG, ≥120 ms apart, and caches Optus tiles per run (one 256 px tile covers ~3.9 km, so nearby points cost nothing extra). A 1,500 km route at 5 km spacing is ~300 Telstra calls, ~300 TPG calls and ~900 Optus tile fetches, and takes about two minutes.

If a carrier redeploys its map the block for that carrier comes back `unknown` with a clear `error`; other carriers are unaffected. The Optus tile layer version and legend are read from the map's configuration at the start of each run and verified with one known tile before any point is graded, and TPG's API base is read from the map's runtime config, so a rolled version is handled without a redeploy of this Actor. Please open an issue if a carrier stays `unknown` for more than a day.

### Pricing

Pay-per-event: one `coverage_point` event per row that at least one carrier answered (`status` `ok` or `partial`), whatever the number of carriers requested. Rows with `status: unknown` are not charged. No platform-usage pass-through. A route given by `origin`/`destination` is computed by the Directions, Routing & Distance Matrix API actor and billed on that actor (about $0.005 for a two-place-name route), outside this run's spending limit; a failed route lookup charges nothing here, though the routing actor may still charge its start event and $0.001 per place name it resolved before the route failed.

### Limitations

- Australia only (bounding box check on input; the carriers have nothing to say elsewhere).
- No 3G (shut down 2024), NB-IoT, or fixed-wireless layers, though Optus publishes them.
- Routing is delegated to the Directions, Routing & Distance Matrix API actor (billed there, see Route by name). A coordinate list joined by straight lines between towns is *not* the highway; give origin/destination or the real polyline.
- Grades are those published by the carriers on the day; they are not archived, so re-running later can differ after a model refresh.

### For agents and pipelines

- Join on `input.id` (echoed) or `input.index` (0-based position in the combined point + route list).
- With `origin`/`destination`, read `OUTPUT.route.locations[].label` to confirm what the place names matched; a route-lookup failure ends the run with no rows, a `route lookup failed: …` status message and an `OUTPUT` holding only `route.{actor, runId, error}` and `warnings`.
- Read `OUTPUT` from the default key-value store for the summary; don't recompute stretches from rows unless you need a different threshold.
- For a map, read the `GEOJSON` record (see GeoJSON output) rather than rebuilding lines from rows.
- Check `status` and each carrier's `status` before reading grades. `best[tech].grade` is `null` only when every requested carrier is `unknown` at that point.
- Route stretches are half-open: `[fromKm, toKm)`, where each sample stands for the route up to the next sample. A single weak sample is one `stepKm` long.

### FAQ

#### Where are the mobile black spots on my road trip?

Give `origin` and `destination` (add `waypoints` for the road you will actually drive) and read `OUTPUT`: `dead4G` lists every No Coverage stretch per carrier with start and end km and coordinates, `weak4G` every Basic-or-worse one, and `best` says whether *any* network covers each stretch.

#### Which carrier is best at this address or along this road?

Pass the address's coordinates as `points` (or the route) with all carriers. Each row's `best` names the carriers with the best grade there; for a route, `OUTPUT.carriers.<carrier>.routeKm` gives kilometres per grade, so the carrier with the most Good and the fewest No Coverage kilometres wins. Addresses must be coordinates here; for a place name, use it as a route's `origin`.

#### Is this a real signal measurement?

No. It is each carrier's own prediction under the ACMA coverage standard, outdoor at ground level, on a 100 m grid; indoors and inside a car are worse. Only Vodafone/TPG publishes a predicted signal strength in dBm; Telstra and Optus give the grade only. See Reading the grades.

#### Does it cover Boost, ALDI Mobile, Belong, amaysim, Felix…?

Yes, through the network each brand runs on: see Coverage of carriers. Telstra's MVNOs other than Boost use the smaller wholesale footprint, so request `telstra_wholesale` for them.

#### How do I use it from an AI agent (MCP), n8n, Make or my own code?

Through the Apify MCP server (`mcp.apify.com`) an agent can find this Actor with `search-actors`, read this README and call it with the fields in the Input section. From n8n, Make, Zapier or your own code, use Apify's integration for that tool or the Apify API and client libraries with the same input JSON. Join rows back to your input on `input.id` or `input.index`, and read counts from the dataset or `OUTPUT`, not from the run summary, which can lag the dataset by a second or two. See For agents and pipelines.

### Disclaimer

Coverage grades are © the respective carriers and are reproduced as published by their public coverage checkers under the ACMA industry standard; this Actor is not affiliated with Telstra, Optus, TPG Telecom, SpatialBuzz, Mapshed or the ACMA. Coverage is predicted, outdoor-only and changes over time. Verify before relying on it for safety-critical purposes.

# Actor input Schema

## `points` (type: `array`):

Places to check mobile reception at (a house, campsite, caravan park, work site): one row per point with each carrier's predicted 4G/5G grade. Objects `{"lat": -27.4648, "lng": 153.0190, "id": "brisbane-roma-st"}` (`lon`/`latitude`/`longitude` also accepted), or `{"address": "12 Smith St, Fitzroy VIC 3065", "id": "smith-st"}` to have the address geocoded for you (see Addresses). `id` is optional and echoed back for joining. Australia only. Up to 5000 points per run including route samples.

## `addresses` (type: `array`):

Street addresses or place names to check phone signal at, one per line (`"12 Smith St, Fitzroy VIC 3065"`, `"Coonabarabran NSW"`). Each is geocoded through the Directions, Routing & Distance Matrix API actor (davidar/openstreetmap-directions-api) under your account — $0.001 per address on that actor, nothing for an address it cannot place — then graded like a point; the row carries the address and the matched place. Australia only; up to 1000 per run. Paid Apify plans only (the free tier has no geocoder: pass `points` with coordinates instead). To keep your own ids, use `points` objects with `address` and `id`.

## `origin` (type: `string`):

Where the road trip or drive starts, when you want the route computed for you: a place name or address (`"Brisbane QLD"`, `"Roma St, Brisbane"`) or `"lat,lng"` (`"-27.4648,153.019"`, latitude first). Needs `destination`. The route is computed by the Directions, Routing & Distance Matrix API actor (davidar/openstreetmap-directions-api), run under your account: its per-route ($0.003) and per-place-name ($0.001) charges appear on that actor in your billing, not on this one. Free Apify plans get its community-router tier: coordinates only, car only. `polyline` and `coordinates` take precedence when given.

## `destination` (type: `string`):

Where the drive ends: a place name or address, or `"lat,lng"` (latitude first). Needs `origin`. Routed by the Directions, Routing & Distance Matrix API actor (davidar/openstreetmap-directions-api) under your account — see Origin for what that costs.

## `waypoints` (type: `array`):

Stops to route through between origin and destination, in order, so coverage is checked on the road you will actually drive (the router takes the shortest road, not necessarily the highway). Each is a string: a place name (`"Gilgandra NSW"`) or `"lat,lng"`, like origin and destination. Optional, up to 18. Each place name is one geocode charge on the routing actor.

## `profile` (type: `string`):

How the origin/destination route is travelled, which decides the roads it takes: one of the values below, default `car`. The free-plan community router serves `car` only.

## `polyline` (type: `string`):

Your own route, if you already have directions from another API: an encoded polyline string (Google Directions `overview_polyline.points`, OSRM, Mapbox, Valhalla). Resampled every `stepKm`; each sample becomes a row with `routeKm`. Pass the directions polyline, not your own sampled points. Takes precedence over `coordinates` and origin/destination; can be combined with `points`.

## `polylinePrecision` (type: `integer`):

Decoding precision of `polyline`, set by the service that produced it: 5 for Google Directions and OSRM's default; 6 for Mapbox Directions, Valhalla and OSRM `polyline6`.

## `coordinates` (type: `array`):

Your own route as a list of vertices, instead of a polyline: `[lat, lng]` number pairs, latitude first (the same order as origin/destination), e.g. `[[-27.4648, 153.019], [-28.55, 150.31]]`. Pass the road geometry: vertices are joined by straight lines. A pair in GeoJSON `[lng, lat]` order is refused with a hint, never swapped for you. Ignored when `polyline` is set; takes precedence over origin/destination.

## `stepKm` (type: `number`):

How often to check coverage along the route, in km between samples (each sample is one row and one charge). The carriers' models are 100 m grids; 5 km catches town/scrub transitions on a highway, 1 km is thorough. Points per run are capped at 5000.

## `carriers` (type: `array`):

Which mobile networks to grade, as a list of these values. `telstra` = Telstra retail network (Telstra, Boost). `optus` = Optus network (Optus, amaysim, Coles Mobile…). `tpg` = TPG Telecom / Vodafone network (Vodafone, TPG, iiNet, Kogan, Lebara, felix…), the only one that also returns predicted signal strength in dBm. `telstra_wholesale` = Telstra's MVNO footprint (ALDI Mobile, Belong, Woolworths, Tangerine…), smaller than retail. Default: telstra, optus, tpg. Grades are carrier predictions, outdoor at ground level, not measurements.

## `concurrency` (type: `integer`):

How many points are checked in parallel (1–8, default 4); leave it unless a run is slow. The carriers' checkers are unofficial shared endpoints; requests per host are capped regardless of this value (Telstra and TPG 2 in flight, ≥120 ms apart; Optus tiles 4).

## Actor input object example

```json
{
  "points": [
    {
      "id": "brisbane-roma-st",
      "lat": -27.4648,
      "lng": 153.019
    },
    {
      "id": "coonabarabran",
      "lat": -31.275,
      "lng": 149.278
    },
    {
      "id": "pilliga",
      "lat": -30.6135,
      "lng": 149.5766
    }
  ],
  "profile": "car",
  "polylinePrecision": 5,
  "stepKm": 5,
  "carriers": [
    "telstra",
    "optus",
    "tpg"
  ],
  "concurrency": 4
}
```

# Actor output Schema

## `points` (type: `string`):

One row per input point / route sample: carriers.{telstra,optus,tpg,telstra\_wholesale}.data\['4G'|'5G'|'5G\_NSA'|'5G\_SA'], best\['4G'|'5G'], point.routeKm. Tri-state: status unknown is a fetch failure, never No Coverage.

## `summary` (type: `string`):

Per carrier and cross-carrier best: grade counts, route kilometres per grade, weak4G / dead4G stretches with km and coordinates, telstraWholesale.differsFromRetail. With addresses, a geocoding block {actor, runId, requested, resolved, failed\[] {id, address, status, error}, warnings\[]}. With origin/destination, a route block from the Directions, Routing & Distance Matrix API actor (davidar/openstreetmap-directions-api): actor, runId, profile, distanceKm, durationMin, locations\[] (query, matched label, lat, lng), warnings. If the route lookup fails the run has no rows and OUTPUT holds only route {actor, runId, error} and warnings. OUTPUT.geojson = {record: 'GEOJSON', features: N} points at the map record.

## `geojson` (type: `string`):

RFC 7946 FeatureCollection, positions \[lng, lat]. One LineString per consecutive pair of route samples, graded as the sample it starts at (\[fromKm, toKm)): fromKm, toKm, km, <carrier>4G / <carrier>5G, best4G, best5G, dead4G (any requested carrier No Coverage on 4G), worst4G. One Point per point-mode row: index, id, <carrier>4G / <carrier>5G, best4G, best5G. Unknown grades are null, never No Coverage. Data only; style it in any map library.

# 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 = {
    "points": [
        {
            "id": "brisbane-roma-st",
            "lat": -27.4648,
            "lng": 153.019
        },
        {
            "id": "coonabarabran",
            "lat": -31.275,
            "lng": 149.278
        },
        {
            "id": "pilliga",
            "lat": -30.6135,
            "lng": 149.5766
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("davidar/au-mobile-coverage").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 = { "points": [
        {
            "id": "brisbane-roma-st",
            "lat": -27.4648,
            "lng": 153.019,
        },
        {
            "id": "coonabarabran",
            "lat": -31.275,
            "lng": 149.278,
        },
        {
            "id": "pilliga",
            "lat": -30.6135,
            "lng": 149.5766,
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("davidar/au-mobile-coverage").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 '{
  "points": [
    {
      "id": "brisbane-roma-st",
      "lat": -27.4648,
      "lng": 153.019
    },
    {
      "id": "coonabarabran",
      "lat": -31.275,
      "lng": 149.278
    },
    {
      "id": "pilliga",
      "lat": -30.6135,
      "lng": 149.5766
    }
  ]
}' |
apify call davidar/au-mobile-coverage --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,davidar/au-mobile-coverage"
        }
    }
}
```

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/AsivN8DUzsggcW7Ol/builds/xl7q88P5AC8e9fLkp/openapi.json
