# Virgin Voyages Scraper - Complete Cruise Data Extractor (`sercul/virgin-voyages-scraper`) Actor

Virgin Voyages pricing API - 5 currencies (USD, GBP, AUD, CAD, EUR), per-person lead fares with the advertised original price, full day-by-day itineraries and booking links. No proxy needed. Ideal for OTAs, comparison sites and price analysts.

- **URL**: https://apify.com/sercul/virgin-voyages-scraper.md
- **Developed by:** [Jeremy G](https://apify.com/sercul) (community)
- **Categories:** Travel, Other
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 results

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

## Virgin Voyages Scraper — Complete Cruise Data Extractor

Extract **every Virgin Voyages sailing with its lead per-person price, dates, ship and full day-by-day itinerary** in five currencies, and optionally **every cabin class and grade with its own price**. Built for travel agencies, price comparison sites, affiliate marketers and analysts.

### Why Choose This Scraper?

- ✅ **5 pricing markets** — USD, GBP, AUD, CAD and EUR, each a complete catalog
- ✅ **Whole catalog per run** — every listed sailing across all four ships, ~2 years out
- ✅ **Per-person pricing** with the advertised original fare alongside the current one
- ✅ **Optional full cabin grid** — all five cabin classes and every grade, with prices, availability, room sizes and photos
- ✅ **Full itinerary with day numbers** on every sailing; optional sea-day-aware itinerary and canonical itinerary page link
- ✅ **No proxy required** — a plain, direct connection works out of the box
- ✅ **Fast and cheap** — a full market is a handful of requests and finishes in seconds

### Use Cases

- **Travel agencies & OTAs** — track Virgin Voyages fares and promotions daily
- **Affiliate / comparison sites** — list the full Virgin inventory with deep links
- **Price analysts** — follow fare curves and promotion cadence per sailing
- **Multi-currency monitoring** — compare the same sailing across USD, GBP, AUD, CAD and EUR

### Supported Markets

| Region | Output Currency |
|--------|-----------------|
| `en_US` | USD |
| `en_GB` | GBP |
| `en_AU` | AUD |
| `en_CA` | CAD |
| `it_IT` | EUR |

Virgin Voyages publishes one price list per currency; pick the currency you want to monitor with `region`.

### Input

| Parameter | Type | Description | Default |
|-----------|------|-------------|---------|
| `region`\* | string | Market / currency to scrape | `en_US` |
| `maxRows` | number | Maximum sailings to return (1–5000) | `50` |
| `enrichDetails` | boolean | Itinerary links + sea days: each sailing's itinerary page link and a day-by-day itinerary that includes sea days (one extra request per sailing) | `false` |
| `enrichCabins` | boolean | Full cabin grid: every cabin class and grade per sailing, with original prices, availability, room sizes and images (one extra request per sailing) | `false` |
| `proxyConfiguration` | object | Standard Apify proxy settings | No proxy |
| `maxRequestRetries` | number | Retries for failed requests (Advanced) | `5` |
| `requestHandlerTimeoutSecs` | number | Request timeout in seconds (Advanced) | `60` |

> Virgin Voyages needs **no proxy**: leave `proxyConfiguration` as it is for a direct connection.
> Set `maxRows` to `1000` to get the whole catalog.

### Cabin Classes

Virgin Voyages sells five cabin classes. By default each sailing's record carries the **lowest-priced class that day** as a dynamic field, together with the exact cabin grade it came from. With `enrichCabins: true` every class is priced and every grade is listed:

| Key | Cabin class |
|-----|-------------|
| `INSIDER` | Insider (interior) |
| `SEA_VIEW` | Sea View (ocean view) |
| `SEA_TERRACE` | Sea Terrace (balcony) |
| `ROCKSTAR_SUITES` | RockStar Suites |
| `MEGA_ROCKSTAR` | Mega RockStar suites |

Without `enrichCabins`, only the cheapest class is observed per sailing; classes that are not the cheapest on a given day are not reported (they are not sold out — simply not the lead fare). With `enrichCabins`, each priced class gets `price_{CURRENCY}_{CLASS}` (per person), `brochurePrice_{CURRENCY}_{CLASS}` (the advertised original fare), `grade_{CURRENCY}_{CLASS}` (the cheapest grade), `classification_{CURRENCY}_{CLASS}` and `availability_{CURRENCY}_{CLASS}`, plus:

- `cabinClasses[]` — per class: `pricePerPerson`, `originalPerPerson`, `discountPerPerson`, `leadGrade`, `roomSize`, `maxOccupancy`, `image`
- `cabinGrades[]` — every grade (e.g. `IZ`, `VW`, `TC`, `SS`, `SM`): `available`, `pricePerPerson`, `originalPerPerson`, `fareClass`, `roomSize`, `balconySize`, `maxOccupancy`, `image`
- `cabinImages` — one representative photo per class

### Output

Each record is a single sailing with:

- Sailing and itinerary identifiers (`cruiseId`, `itineraryId`)
- Ship name and code, departure and arrival ports, duration (nights)
- Departure and arrival dates
- Lead **per-person** price with currency, the advertised original fare (`originalPrice`) and per-person taxes (`taxAmount`)
- Ports of call with day numbers (`portsList`, `portsOfCall`); with `enrichDetails`, sea days are included as "At Sea"
- Dynamic lead-cabin fields: `price_{CURRENCY}_{CLASS}`, `classification_{CURRENCY}_{CLASS}`, `grade_{CURRENCY}_{CLASS}`
- `source_url` — booking planner link with the itinerary preselected; with `enrichDetails`, `itineraryUrl` adds the sailing's own itinerary page
- `platform`, `company`, `locale` — for multi-market deduplication
- `tripType`, `classificationCodes` (Virgin's promotion and theme tags such as `10%`, `WEEKEND`, `HOLIDAY`), `isAccessible`, `weekend`
- With `enrichCabins`: every cabin class and grade priced per person, with original prices, discounts, availability, room sizes and cabin photos (see Cabin Classes)

#### Sample Output

A real `en_US` record with `enrichDetails` and `enrichCabins` on (2026-10-23). `portsList`, `cabinClasses` and `cabinGrades` are cut to their first entries here; the full record has every port, all 5 classes and 23 grades.

```json
{
  "cruiseId": "SC2803117NSJRP",
  "itineraryId": "7NSJRP",
  "title": "Southern Caribbean Cruise",
  "shipName": "Scarlet Lady",
  "shipId": "SC",
  "departurePort": { "name": "San Juan, Puerto Rico", "code": "SJU" },
  "arrivalPort": { "name": "San Juan, Puerto Rico", "code": "SJU" },
  "departureDate": "2028-03-11",
  "arrivalDate": "2028-03-18",
  "duration": "7",
  "price": { "amount": "903", "currency": "USD" },
  "originalPrice": "1268",
  "taxAmount": "224",
  "occupancy": 2,
  "price_USD_INSIDER": "903",
  "brochurePrice_USD_INSIDER": "1268",
  "classification_USD_INSIDER": "Insider",
  "grade_USD_INSIDER": "IZ",
  "availability_USD_INSIDER": "available",
  "cabinClassesPriced": 5,
  "cabinClasses": [
    { "cabinClass": "INSIDER", "name": "Insider", "leadGrade": "IZ", "pricePerPerson": 903, "originalPerPerson": 1268, "discountPerPerson": 365, "roomSize": "105-177", "maxOccupancy": "1-4" }
  ],
  "cabinGrades": [
    { "cabinClass": "INSIDER", "grade": "IN", "name": "The Insider", "available": true, "pricePerPerson": 1075, "originalPerPerson": 1532, "fareClass": "BASE", "roomSize": "177", "maxOccupancy": "4" }
  ],
  "portsList": [
    { "portName": "San Juan, Puerto Rico", "dayIndicator": "1" },
    { "portName": "Charlotte Amalie, St. Thomas", "dayIndicator": "2" },
    { "portName": "At Sea", "dayIndicator": "3" }
  ],
  "destinationNames": ["Caribbean"],
  "classificationCodes": ["10%", "WEEKEND"],
  "tripType": "Round trip",
  "platform": "virgin-voyages-en_US",
  "company": "virgin-voyages",
  "locale": "en_US",
  "currency": "USD",
  "source_url": "https://www.virginvoyages.com/book/voyage-planner/find-a-voyage?sailors=2&selectedPackages=7NSJRP",
  "itineraryUrl": "https://www.virginvoyages.com/itinerary/caribbean/7-night-southern-caribbean-cruise-on-11-mar-2028-from-san-juan"
}
```

### Runtime & Cost

- **Typical run:** under a minute for a full market; about 5 minutes with both `enrichDetails` and `enrichCabins` on (~400 sailings, two extra requests each)
- **Volume:** a few hundred sailings per market (the complete live catalog)
- **Memory:** 512 MB
- **Proxy:** Not needed

### Usage

```json
{
  "region": "en_GB",
  "maxRows": 1000,
  "enrichDetails": true,
  "enrichCabins": true
}
```

### Notes

- All prices are **per person**, based on two adults sharing a cabin (`occupancy: 2`), and match the "per Sailor" fare shown on virginvoyages.com
- Taxes and fees are **not included** in `price`; the per-person amount is reported separately in `taxAmount`
- `originalPrice` is the fare Virgin advertises as the pre-promotion price for the same cabin
- With `enrichCabins`, `price` is the cheapest cabin class the booking engine prices, which is what checkout charges. When Virgin reprices, its voyage search can show the previous fare for a few hours; that search value is kept in `searchLeadPrice`
- One output record is produced **per sailing** (departure date), not per itinerary
- Sailings without a price are skipped automatically
- For affiliate tracking, append your affiliate parameters to `source_url` on the consuming side

### Related Actors

Looking to build a full cruise pricing dataset? Pair this with:

- [Royal Caribbean Scraper](https://apify.com/sercul/royal-caribbean) — multi-market, per-cabin pricing
- [Norwegian (NCL) Scraper](https://apify.com/sercul/norwegian-cruise-scraper) — multi-market, enrichable details
- [Celebrity Cruises Scraper](https://apify.com/sercul/celebrity-cruises) — multi-market, service charges included
- [Princess Cruises Scraper](https://apify.com/sercul/princess-cruise-scraper) — multi-market, per-cabin availability counts
- [MSC Cruises Scraper](https://apify.com/sercul/msc-cruises-scraper) — US, UK and five European markets
- [Costa Cruises Scraper](https://apify.com/sercul/costa-cruises) — European markets plus the US
- [Carnival Cruises Scraper](https://apify.com/sercul/carnival-cruises) — US and Australia, high volume
- [Disney Cruise Line Scraper](https://apify.com/sercul/disney-cruises-scraper) — multi-market, cabin-level pricing
- [Holland America Line Scraper](https://apify.com/sercul/hal-cruises-scraper) — five currencies, per-cabin pricing
- [AIDA Cruises Scraper](https://apify.com/sercul/aida-cruise-scraper) — German market, cruise-only fares

### Support

Issues or custom requests? Email **support@track.cruises**.

# Actor input Schema

## `region` (type: `string`):

Market / pricing currency to scrape

## `maxRows` (type: `integer`):

Maximum number of sailings to return (the full catalog is a few hundred)

## `enrichDetails` (type: `boolean`):

Add each sailing's itinerary page link and a day-by-day itinerary that includes sea days. One extra request per sailing.

## `enrichCabins` (type: `boolean`):

Price every cabin class and grade per sailing, with original prices, availability, room sizes and images. Without it you get the lowest fare only. One extra request per sailing.

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

Virgin Voyages needs no proxy, so the default is a direct connection. If you switch on Apify Proxy without picking a group or country, RESIDENTIAL in the region's own country is used.

## `maxRequestRetries` (type: `integer`):

Maximum number of retries for failed requests

## `requestHandlerTimeoutSecs` (type: `integer`):

Timeout for HTTP requests in seconds

## Actor input object example

```json
{
  "region": "en_US",
  "maxRows": 50,
  "enrichDetails": false,
  "enrichCabins": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "maxRequestRetries": 5,
  "requestHandlerTimeoutSecs": 60
}
```

# Actor output Schema

## `cruises` (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 = {
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("sercul/virgin-voyages-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 = { "proxyConfiguration": { "useApifyProxy": False } }

# Run the Actor and wait for it to finish
run = client.actor("sercul/virgin-voyages-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 '{
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call sercul/virgin-voyages-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sercul/virgin-voyages-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/UEpHoeVhNhJqhVYBi/builds/3gSCM55IS0Vb3odcV/openapi.json
