# redBus Scraper – Bus Schedules, Fares & Seat Availability (`rl1987/redbus-api-scraper`) Actor

Search redBus for every bus between two cities on a date, in any of its 8 markets (India, Singapore, Malaysia, Indonesia, Vietnam, Cambodia, Colombia, Peru). One row per service: operator, bus type, departure and arrival, duration, fares in local currency, seats left, rating, boarding points.

- **URL**: https://apify.com/rl1987/redbus-api-scraper.md
- **Developed by:** [R.L.](https://apify.com/rl1987) (community)
- **Categories:** Travel
- **Features:** Limited permissions
- **Stats:** 26 total users, 2 monthly users, 98.2% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.54 / 1,000 bus services

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## redBus Scraper — Bus Schedules, Fares & Seat Availability

**redBus Scraper** searches redBus for every bus service running between two cities on a given
date and returns one clean row per service: operator, bus type, departure and arrival times,
journey duration, fares in the market's own currency, seats left, rating and reviews, and
boarding/dropping points. It reads redBus's own mobile API directly — no headless browser, no
HTML parsing — and exports to **JSON, CSV, Excel, XML or the Apify API**.

It is **read-only**: it searches and reports. It never books, holds or pays for a seat.

***

### Why use this redBus Scraper?

- **No code required** — type two city names, click **Start**, download your data.
- **All eight redBus markets** — India, Singapore, Malaysia, Indonesia, Vietnam, Cambodia, Colombia and Peru, each with its own cities, operators and currency.
- **Fast & accurate** — reads redBus's own app API and returns structured JSON.
- **Rich, structured data** — fares, seat counts by type, amenities, offers, ratings, boarding points.
- **Pagination with de-duplication** — pages are collected to your `maxItems` cap and repeated services are dropped.
- **Transparent pay-per-event pricing** — you are charged for what a run delivers; the **Pricing** tab lists the events and their current prices.

***

### What can you do with redBus data?

- **Fare monitoring** — track how a route's fares move as the travel date approaches.
- **Route & capacity research** — who runs a corridor, with what bus types, at what times.
- **Occupancy signals** — watch `availableSeats` against `totalSeats` over repeated runs.
- **Travel apps & dashboards** — feed timetables and fares into your own product.

***

### Which countries, cities and routes can I search?

Set `country` to the redBus market you want. City names are resolved through redBus's own
autocomplete, so you type them the way a passenger would. Every pair below was verified against
that autocomplete:

| `country` | Currency | Example route |
| --- | --- | --- |
| `india` | INR | Bengaluru → Chennai, Mumbai → Pune, Delhi → Jaipur, Hyderabad → Goa |
| `singapore` | SGD | Singapore → Kuala Lumpur |
| `malaysia` | MYR | Kuala Lumpur → Penang, Johor Bahru → Kuala Lumpur |
| `indonesia` | IDR | Jakarta → Bandung, Surabaya → Jakarta |
| `vietnam` | VND | Ho Chi Minh → Da Lat, Hanoi → Ho Chi Minh |
| `cambodia` | USD | Phnom Penh → Siem Reap |
| `colombia` | COP | Bogota → Medellin |
| `peru` | PEN | Lima → Arequipa, Lima → Cusco |

City IDs are per-market, so the same name in two markets is two different places — the Actor
keys its city cache by market to keep them apart. An unsupported `country` fails the run with a
clear message instead of quietly searching India.

***

### How do I scrape redBus? (3 steps)

1. **Enter the route** — `source` and `destination` city names (both required).
2. **Pick the date and market** — `dateOfJourney` and `country`; set a `maxItems` cap.
3. **Run & export** — click **Start**, then download the dataset as JSON/CSV/Excel or fetch it via the API.

***

### What input does it take?

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `source` | string | `Bengaluru` | City you are travelling from. Resolved through redBus's own autocomplete. Required. |
| `destination` | string | `Chennai` | City you are travelling to. Required. |
| `dateOfJourney` | string | today + 7 days | `YYYY-MM-DD`, or a relative value like `7 days` / `2 weeks` / `1 month`. Empty, unparseable or past dates fall back to a week from today. |
| `country` | select | `india` | Which redBus market to search: `india`, `singapore`, `malaysia`, `indonesia`, `vietnam`, `cambodia`, `colombia`, `peru`. |
| `pageSize` | integer | `20` | Services requested per API call (max 100). |
| `maxItems` | integer | `100` | Maximum services to return (`0` = every service on the route). |
| `proxyConfiguration` | object | Apify Proxy | Route requests through a proxy. |

#### Example input

```jsonc
{
  "source": "Bengaluru",
  "destination": "Chennai",
  "dateOfJourney": "7 days",
  "country": "india",
  "pageSize": 20,
  "maxItems": 100,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

***

### What does each row contain?

One row is one bus service on the searched date.

```jsonc
{
  "id": 47150520,
  "routeId": 47150520,
  "serviceId": "...",
  "travelsName": "SABARI TRAVELS",
  "busType": "Bharat Benz A/C Sleeper (2+1)",
  "serviceName": "BGL - CHE  ",
  "isAc": true,
  "isSleeper": true,
  "isDirectBus": true,
  "amenities": ["..."],
  "departureTime": "2026-08-25 23:40:00",
  "arrivalTime": "2026-08-26 06:00:00",
  "journeyDurationMin": 380,
  "dateOfJourney": "2026-08-25",
  "boardingPoint": "Madiwala",
  "droppingPoint": "Koyambedu",
  "boardingPointCount": 12,
  "droppingPointCount": 9,
  "fareList": [2089.0, 2639.0],
  "minFare": 2089.0,
  "maxFare": 2639.0,
  "vendorCurrency": "INR",
  "availableSeats": 24,
  "totalSeats": 37,
  "availableWindowSeats": 6,
  "rating": 4.9,
  "numberOfReviews": "1275",
  "offers": [{ "campaignCode": "...", "description": "...", "discount": "..." }],
  "source": "Bengaluru",
  "destination": "Chennai"
}
```

#### Data table

| Group | Fields |
| --- | --- |
| Identity | `id` / `routeId` (same value), `serviceId`, `operatorId`, `travelsName` (operator), `serviceName`, `operatorLogoUrl` |
| Bus | `busType`, `busTypeId`, `isAc`, `isSleeper`, `isDirectBus`, `viaRoute`, `amenities`, `isLiveTrackingAvailable`, `isMTicketEnabled`, `isPartialCancellationAllowed`, `maxSeatsPerTransaction`, `serviceNotes`, `inventoryTags`, `busImageCount` |
| Schedule | `departureTime`, `arrivalTime`, `journeyDurationMin`, `dateOfJourney`, `firstBpTime` |
| Boarding / dropping | `boardingPoint`, `boardingPointId`, `droppingPoint`, `droppingPointId`, `boardingPointCount`, `droppingPointCount` |
| Fares | `fareList` (every fare on the bus), `minFare`, `maxFare`, `vendorCurrency`, `fareDetailsBySeatType` |
| Availability | `availableSeats`, `totalSeats`, `availableWindowSeats`, `availableSingleSeats`, `availableAisleSeats`, `availableUpperSeats`, `availableLowerSeats`, `isSeatLayoutAvailable` |
| Ratings | `rating`, `numberOfReviews`, `busScore`, `perzScore` |
| Offers & status | `offers` (campaign code, description, discount), `campaignType`, `programList`, `isRescheduled`, `rescheduleTime` |
| Route context | `source`, `destination` (as redBus labels the parent cities) |

***

### What do these bus terms mean?

- **Service** — one departure by one operator on the searched date. A route run three times a
  day is three rows.
- **`routeId`** — redBus's identifier for that service on that route; the Actor also copies it
  to `id` and de-duplicates pages by it, so a service never appears twice in one run.
- **`minFare` / `maxFare`** — the cheapest and dearest seat currently offered on that bus, taken
  from `fareList`. A sleeper bus with seater and berth classes will show a spread.
- **`vendorCurrency`** — the currency the fares are quoted in, which follows the `country` you
  searched (INR, SGD, MYR, IDR, VND, USD, COP, PEN).
- **`availableSeats` / `totalSeats`** — seats still bookable versus the bus's capacity at the
  moment of the search. The `available*Seats` fields break the free seats down by window, aisle,
  single, upper and lower berths.
- **Boarding / dropping point** — where the bus picks up and drops off within each city.
  `boardingPoint` is the operator's standard pickup; `boardingPointCount` says how many
  alternatives that service offers.
- **`busScore` / `perzScore`** — redBus's own internal quality and personalisation scores, passed
  through unchanged.

***

### How much does it cost?

The current price of every event is on the **Pricing** tab of this Actor's page in Apify Store. That tab is generated from the Actor's own pricing record, so it is always current, and your plan's rung is applied automatically. A figure repeated here would be a second copy that drifts out of date.

You can cap what any single run may spend with **Max total charge**.

### How do I run it from my own code?

```bash
curl -X POST "https://api.apify.com/v2/acts/rl1987~redbus-api-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "source": "Bengaluru",
  "destination": "Chennai",
  "dateOfJourney": "7 days",
  "country": "india",
  "maxItems": 100
}'
```

Or with the Apify CLI: `apify call rl1987/redbus-api-scraper -i input.json -o`. You can also
schedule it on Apify — for example the same route every morning, to watch fares move.

***

### FAQ

**Do I need a redBus account or API key?**
No. The Actor calls redBus's own app API with the app's fixed header set, so there is no login,
no cookie and no key to obtain. You only need an Apify account.

**Which countries and currencies does it cover?**
All eight redBus markets: India (INR), Singapore (SGD), Malaysia (MYR), Indonesia (IDR), Vietnam
(VND), Cambodia (USD), Colombia (COP) and Peru (PEN). Fares come back in that market's own
currency, and cities must be named as that market knows them.

**How do I search a date without editing the input every day?**
Give `dateOfJourney` a relative value such as `7 days` or `2 weeks`, and a scheduled run will
always look that far ahead. An empty, unreadable or already-past date is treated as a week from
today rather than returning nothing.

**What happens if no buses run on that route and date?**
redBus answers "no buses available" with an HTTP 200 body rather than an error, and the Actor
treats it as a normal zero-result search: the run finishes successfully with no rows, so you are
not charged for a route that has no service.

**Can it book a seat or return the seat map?**
No. It is read-only: it searches and reports availability. It never books, blocks or pays for a
seat. `isSeatLayoutAvailable` tells you whether redBus has a seat map for that service, but the
map itself is not part of the output.

**Do I need a proxy?**
Apify Proxy is on by default and is enough for normal use. Residential proxies are the safer
choice for large or repeated runs.

**How many rows will one search return?**
One per bus service on that date, typically a handful on a thin route and over a hundred on a
busy corridor. Pages are fetched until redBus runs out of services or your `maxItems` cap is
reached, and services repeated between pages are dropped rather than pushed twice.

**Is scraping this legal?**
You are responsible for how you use the data. Scrape public information only and comply with
redBus's Terms and applicable law.

***

### How does it work?

The Actor talks to redBus's Android app API the way the app does: it resolves both city names
through redBus's `pathfinder` autocomplete (per market), then requests the bus inventory for
`source → destination → date` and pages through it. Requests that fail with a rate-limit or
server error are retried with exponential backoff, and each raw service record is flattened into
the row above.

***

### Good to know

- Fares, seat counts and offers are a snapshot at the time of the run; re-run to see them move.
- Fields can be `null` when redBus does not expose them for a given service.
- City names are market-specific — searching `Kuala Lumpur` in the India market will not find the
  Malaysian city.
- You are the data controller for whatever you collect; comply with applicable law.

***

### Found this useful?

Rate the **redBus Scraper** on Apify — it helps other people find it and helps us keep improving it.

# Actor input Schema

## `source` (type: `string`):

City you are travelling from (e.g. Bengaluru). Resolved via the app's own autocomplete.

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

City you are travelling to (e.g. Chennai). Resolved via the app's own autocomplete.

## `dateOfJourney` (type: `string`):

Travel date. Pick a date (YYYY-MM-DD) or use a relative value like "7 days" / "2 weeks". Leave empty for a week from today. redBus rejects past dates with an HTTP 200 error body rather than a 4xx, so a past date is normalised forward instead of silently returning nothing.

## `pageSize` (type: `integer`):

Number of services per request (max 100).

## `maxItems` (type: `integer`):

Maximum number of bus services to return (0 = all).

## `country` (type: `string`):

Which redBus market to search. City names and prices are market-specific: fares come back in that market's own currency (INR, SGD, MYR, IDR, VND, USD, COP, PEN).

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

Route requests through a proxy (Apify Proxy by default).

## Actor input object example

```json
{
  "source": "Bengaluru",
  "destination": "Chennai",
  "dateOfJourney": "",
  "pageSize": 20,
  "maxItems": 100,
  "country": "india",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "source": "Bengaluru",
    "destination": "Chennai",
    "dateOfJourney": "",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("rl1987/redbus-api-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 = {
    "source": "Bengaluru",
    "destination": "Chennai",
    "dateOfJourney": "",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("rl1987/redbus-api-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 '{
  "source": "Bengaluru",
  "destination": "Chennai",
  "dateOfJourney": "",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call rl1987/redbus-api-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rl1987/redbus-api-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/CTo6fbx8UwpCCPjgZ/builds/QB8UdyvKDp8rFBJYw/openapi.json
