# AllTrails Scraper - Hiking Trail Data (`bovi/alltrails-scraper`) Actor

Collect AllTrails trail data. Get records with location, difficulty, distance, elevation, ratings, route type, activities, features and GPS. Run with a location, keyword or AllTrails URL; no login. Pricing: $0.004 per saved result on Free plan.

- **URL**: https://apify.com/bovi/alltrails-scraper.md
- **Developed by:** [Vitalii Bondarev](https://apify.com/bovi) (community)
- **Categories:** Travel, Lead generation
- **Features:** Limited permissions
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 alltrails scraper - hiking trail data

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

## AllTrails Trail Scraper

Extract hiking, running and biking trail data from [AllTrails](https://www.alltrails.com) by park, state, city, map bounding box, keyword or AllTrails URL, with one flat dataset row per trail. The Free plan charges $0.004 per saved result and $0.00005 per `apify-actor-start` event.

- Build trail directories for parks, states, cities and regions.
- Compare difficulty, distance, elevation, ratings, reviews and route types.
- Map trailheads with latitude and longitude, plus activity and feature filters.
- Download descriptions and optional trail-page details.
- Run without an AllTrails login or API key.

### What you get

| Field family | Fields | Type | Description |
|---|---|---|---|
| Identity | `trailId`, `name`, `url` | `trailId`: integer; others: string | Trail ID, name and page URL |
| Area | `areaName`, `areaPage`, `city`, `state`, `country` | string or null | Park/area, location and country |
| Position | `latitude`, `longitude` | number or null | Trailhead GPS coordinates |
| Distance | `lengthKm`, `lengthMiles` | number or null | Length in kilometres and miles |
| Elevation | `elevationGainM`, `elevationGainFt`, `highestPointM` | number or null | Elevation gain and highest point |
| Difficulty | `difficulty`, `difficultyRating` | string/integer or null | Difficulty label and rating |
| Route | `routeType` | string or null | Loop, Out & Back or Point to Point |
| Ratings | `avgRating`, `reviewCount`, `textReviewCount` | number/integer or null | Average rating and review counts |
| Activity data | `recordingCount`, `photoCount`, `popularity`, `visitorUsage` | number/integer or null | Recordings, photos, popularity and traffic |
| Time | `estimatedTime`, `durationMinutes` | string/integer or null | Estimated completion time |
| Tags | `activities`, `features` | array of strings | Activity and feature arrays |
| Listing content | `description`, `photoUrl` | string or null | Description excerpt and main photo URL |
| Status | `isClosed`, `isPrivateProperty` | boolean or null | Closed and private-property indicators |
| Run metadata | `scrapedAt` | ISO 8601 string | UTC scrape timestamp |
| Optional details | `overview`, `completedCount`, `trackCount`, `obstacles` | string/integer/array or null | Overview, counts, obstacles and fees |
| Optional conditions | `seasonStartMonth`, `seasonEndMonth`, `lowCellService`, `createdAt` | integer/boolean/string or null | Best-season months, cell service and creation date |

A field is `null` when the source does not provide it. Optional detail fields are returned when **Include trail page details** is enabled; that mode opens each trail page and is slower.

### Sample output

This shortened sample keeps one real dataset record and omits nonessential fields.

```json
{
  "trailId": 10006571,
  "name": "Angels Landing Trail",
  "url": "https://www.alltrails.com/trail/us/utah/angels-landing-trail",
  "areaName": "Zion National Park",
  "city": "Springdale",
  "state": "Utah",
  "country": "United States",
  "latitude": 37.2591,
  "longitude": -112.95122,
  "lengthKm": 7.72,
  "elevationGainM": 517.9,
  "difficulty": "strenuous",
  "routeType": "Out & Back",
  "avgRating": 4.9,
  "reviewCount": 42218,
  "activities": ["hiking"],
  "features": ["river", "views", "wild-flowers", "wildlife", "dogs-no", "partially-paved"],
  "scrapedAt": "2026-10-16T06:13:46.652723+00:00"
}
```

### Pricing

The Actor uses pay-per-event billing on the Free plan:

- **`apify-default-dataset-item`: $0.004 per saved dataset result on the Free plan.** One result is one scraped trail with all fields.
- **`apify-actor-start`: $0.00005 per event on the Free plan.** It is charged once per GB of run memory, minimum one event.
- On the Free plan, 1,000 results = 1,000 × $0.004 = **$4.00**, plus the start event.
- On the Free plan, 1,249 results = 1,249 × $0.004 = **$4.996**, plus the start event.
- On the Free plan, 10,000 results = 10,000 × $0.004 = **$40.00**, plus the start event.

You pay only for the events listed above. This Actor does not use the Pay per event + usage option, so compute, proxy traffic and storage are not billed separately. The Apify Free plan includes **$5 of monthly platform usage credit**.

### How to use

1. Choose a search mode: park, state or region, city, coordinates or keyword.
2. Enter the matching location or keyword, or provide optional AllTrails Start URLs.
3. Add difficulty, rating, review, route, activity, feature, traffic, length, elevation or closed-status filters.
4. Set `maxResults`, language and optional trail-page details.
5. Start the Actor and read the flat trail rows from the dataset.
6. Repeat the run through Apify Schedules; weekly is a starting point for a trail-data collection job.

```json
{
  "searchType": "park",
  "park": "Zion National Park",
  "difficulty": ["moderate", "hard"],
  "minRating": 4.5,
  "maxResults": 50,
  "language": "en-US",
  "includeDetails": false
}
```

Export the dataset as JSON or CSV, or read it through the Apify dataset API.

### Input parameters

| Parameter | What it does | Default |
|---|---|---|
| `searchType` | Selects `park`, `state`, `city`, `coordinates` or `keyword`; ignored when `startUrls` is set | `park` |
| `park` | Searches for a park or protected-area name | Not set |
| `state` | Searches for a state or region | Not set |
| `city` | Searches for a city; use `cityState` for same-named cities | Not set |
| `cityState` | Optional city state or region | Not set |
| `north`, `south`, `east`, `west` | Map bounding box for `coordinates` | Not set |
| `keyword` | Free-text search for `keyword` mode | Not set |
| `startUrls` | AllTrails trail, park, city, state or explore-map URLs; overrides `searchType` | Not set |
| `maxResults` | Maximum trails to save; maximum 1000000 | `50` |
| `difficulty` | Keeps `easy`, `moderate`, `hard` or `strenuous` | Not set |
| `minRating` | Minimum average rating from 0 to 5 | Not set |
| `minReviews` | Minimum review count | Not set |
| `routeType` | Keeps `loop`, `out-and-back` or `point-to-point` | Not set |
| `activities` | Keeps trails with at least one selected activity | Not set |
| `features` | Keeps trails containing all selected features | Not set |
| `visitorUsage` | Traffic levels `1` through `4`; 1 is lightest and 4 busiest | Not set |
| `minLengthKm`, `maxLengthKm` | Trail-length range in kilometres | Not set |
| `minElevationGainM`, `maxElevationGainM` | Elevation-gain range in metres | Not set |
| `includeClosed` | Also returns trails marked closed when `true` | `false` |
| `language` | Selects the search language | `en-US` |
| `includeDetails` | Opens trail pages for overview, counts, obstacles, season and cell-service fields | `false` |
| `proxyConfiguration` | Optional proxy; search works without one and Apify Proxy can help when fetching trail pages at volume | Apify Proxy residential configuration |

Supported language values include `en-US`, `en-GB`, `de-DE`, `fr-FR`, `es-ES`, `es-MX`, `it-IT`, `nl-NL`, `nb-NO`, `pl-PL`, `pt-BR`, `pt-PT`, `sv-SE` and `da-DK`.

### Limits and edge cases

| Condition | What you see | What to do |
|---|---|---|
| A park, state or city name does not resolve as an AllTrails location | The search can return no trails | Check the spelling and use AllTrails’ name |
| Filters are too restrictive | An empty or smaller-than-expected dataset | Loosen rating, review, feature, activity or location filters |
| `features` contains multiple values | A trail must contain every selected feature | Remove a feature or use fewer requirements |
| Multiple activities, difficulty levels, route types or traffic levels are selected | A trail can match any selected value in those groups | Select the values that should be accepted |
| `includeDetails` is enabled | Trail-page fields are requested and the run is slower | Leave it disabled when listing fields are sufficient |
| A location has more trails than one search query holds (the search index returns at most 1,000 hits per query) | Only when a location has more than 1,000 trails, the area is divided into trail-length slices; large runs are ordered shorter to longer | Set `maxResults` or use length filters |
| A Start URL is supplied | `searchType` and location fields are ignored | Put the intended AllTrails URL in `startUrls` |
| A Start URL is not a supported AllTrails trail, park, city, state or explore-map URL | That URL is skipped and a warning is logged | Replace it with a supported AllTrails URL |
| A trail-page fetch fails while `includeDetails` is enabled | The trail row is still saved; its optional detail fields are `null` | Run again or use the listing fields |
| A direct trail URL is supplied | The run targets that trail instead of general search filters | Use a park, city, state, map or keyword search for a collection |

### FAQ

#### How much does it cost to scrape AllTrails trails?

On the Free plan, `apify-default-dataset-item` costs **$0.004 per saved result** and `apify-actor-start` costs **$0.00005 per event**. **1,249 results on the Free plan** = **$4.996**, plus the start event. The Apify Free plan includes **$5** of monthly platform usage credit.

#### What does an empty result mean?

The location may not have resolved, its spelling may not match AllTrails, or filters may have removed every trail. Check the spelling and loosen the filters.

#### Do I need an AllTrails login or API key?

No. The documented input does not require an AllTrails login or an API key. Proxy configuration is optional; Apify Proxy can help when fetching trail pages at volume.

#### What source does this Actor use, and is this legal?

The Actor collects public data served by `alltrails.com`, including public trail-search data and trail widget pages. Whether a collection or use is legal or allowed depends on the source terms and applicable law for your use case; review those requirements before using the data.

### Related actors

- [EaseMyTrip Hotels Scraper - Prices, Ratings, Locations](https://apify.com/bovi/easemytrip-scraper)
- [OpenTable Scraper — Reviews, Restaurants & Availability](https://apify.com/bovi/opentable-scraper)
- [Eventim Scraper: Events & Ticket Prices Germany](https://apify.com/bovi/eventim-scraper)

# Actor input Schema

## `searchType` (type: `string`):

How to find trails. Ignored when Start URLs are given.

## `park` (type: `string`):

Name of a park or protected area as AllTrails lists it, e.g. "Yosemite National Park" or "Banff National Park". Used when Search by = Park.

## `state` (type: `string`):

US state or another country's region, e.g. "Colorado", "British Columbia". Used when Search by = State.

## `city` (type: `string`):

City name, e.g. "Denver". Used when Search by = City.

## `cityState` (type: `string`):

Optional, to tell same-named cities apart, e.g. "Colorado" for Denver, CO.

## `north` (type: `number`):

Bounding box north edge. Used when Search by = Coordinates.

## `south` (type: `number`):

Bounding box south edge.

## `east` (type: `number`):

Bounding box east edge (western hemisphere is negative).

## `west` (type: `number`):

Bounding box west edge.

## `keyword` (type: `string`):

Free-text trail search, e.g. "waterfall loop". Used when Search by = Keyword.

## `startUrls` (type: `array`):

Optional AllTrails URLs: trail pages (/trail/...), park pages (/parks/...), city or state pages (/us/colorado/denver) or explore map URLs with b_tl_lat/b_tl_lng/b_br_lat/b_br_lng. When set, Search by is ignored.

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

Maximum number of trails to save.

## `difficulty` (type: `array`):

Keep only these AllTrails difficulty levels.

## `minRating` (type: `number`):

Minimum average star rating (0-5).

## `minReviews` (type: `integer`):

Minimum number of reviews.

## `routeType` (type: `array`):

Keep only these route shapes.

## `activities` (type: `array`):

Keep trails that list at least one of these activities.

## `features` (type: `array`):

Keep trails that have all of these features.

## `visitorUsage` (type: `array`):

AllTrails visitor usage level, 1 = lightest traffic, 4 = busiest.

## `minLengthKm` (type: `number`):

Minimum trail length in kilometres.

## `maxLengthKm` (type: `number`):

Maximum trail length in kilometres.

## `minElevationGainM` (type: `number`):

Minimum elevation gain in metres.

## `maxElevationGainM` (type: `number`):

Maximum elevation gain in metres.

## `includeClosed` (type: `boolean`):

Also return trails AllTrails marks as closed.

## `language` (type: `string`):

Language of trail names and descriptions.

## `includeDetails` (type: `boolean`):

Open each trail's page for its full overview, completion and recording counts, obstacles, best season and cell-service flag. Slower.

## `proxyConfiguration` (type: `object`):

Optional proxy. The trail search works without one; Apify Proxy helps when fetching trail pages at volume.

## Actor input object example

```json
{
  "searchType": "park",
  "park": "Zion National Park",
  "state": "Colorado",
  "city": "Denver",
  "cityState": "Colorado",
  "north": 40,
  "south": 39.6,
  "east": -104.7,
  "west": -105.3,
  "keyword": "waterfall",
  "maxResults": 50,
  "includeClosed": false,
  "language": "en-US",
  "includeDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Dataset with the scraped trails.

# 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 = {
    "searchType": "park",
    "park": "Zion National Park",
    "state": "Colorado",
    "city": "Denver",
    "cityState": "Colorado",
    "north": 40,
    "south": 39.6,
    "east": -104.7,
    "west": -105.3,
    "keyword": "waterfall",
    "maxResults": 50,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("bovi/alltrails-scraper").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 = {
    "searchType": "park",
    "park": "Zion National Park",
    "state": "Colorado",
    "city": "Denver",
    "cityState": "Colorado",
    "north": 40,
    "south": 39.6,
    "east": -104.7,
    "west": -105.3,
    "keyword": "waterfall",
    "maxResults": 50,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("bovi/alltrails-scraper").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 '{
  "searchType": "park",
  "park": "Zion National Park",
  "state": "Colorado",
  "city": "Denver",
  "cityState": "Colorado",
  "north": 40,
  "south": 39.6,
  "east": -104.7,
  "west": -105.3,
  "keyword": "waterfall",
  "maxResults": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call bovi/alltrails-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,bovi/alltrails-scraper"
        }
    }
}
```

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/bRsbOfm2Om0MuBYB7/builds/XVWFgzp6cXYz9ls7g/openapi.json
