# Changelog of Cruise Data Feed: Lines, Itineraries, Ports & Prices (`vulnv/cruise-data-feed`) Actor

- **URL**: https://apify.com/vulnv/cruise-data-feed/changelog.md
- **Full Actor documentation**: https://apify.com/vulnv/cruise-data-feed.md

## Changelog

### 1.4 — continued

Shipped in place, per the one-version-overwritten-in-place decision recorded in
187c5e7. Deploy with `python apify/deploy_cruise_data_feed.py` — a plain `apify push`
drops the Actor's API key secret.

- **A multi-line request now returns every line you asked for.** The Actor issues one
  request per cruise line, and it used to page the first line until `maxResults` ran
  out — so a 3-line, 40-result run came back 40 rows from line one and nothing from
  lines two and three. The budget is now shared: each round gives every line an equal
  slice of what is left, so the same run returns 14 / 13 / 13. A line with fewer
  sailings than its share hands the remainder back to the others instead of losing it,
  so you still receive the full `maxResults` wherever the catalogue can supply it.
- **Two new filters for data quality, both off by default.** `onlyWithBookingUrl`
  keeps only sailings carrying a direct booking link (26.0% of upcoming sailings);
  `scrapedSince` keeps only sailings last confirmed against their source on or after a
  date you choose, matched against each record's own `last_seen_at` (26.8% were last
  read before 2026-06-28). Both are applied by the feed itself, so neither shortens
  your results: `maxResults` still means the number of records you receive. Until now
  `minPrice` was the only input that happened to exclude stale rows, which was a
  coincidence rather than a contract.
- **Every run reports what it returned.** The log now states how many stored records
  carry a booking link and how many were confirmed in the last 30 days, plus the
  per-cruise-line split, so a thin result is visible rather than inferred.
- **The cruise-line dropdown offers all 70 bookable brands and stays that way.** It
  had drifted to 67, so Atlas Ocean Voyages, Aurora Expeditions, Paul Gauguin, Scenic
  Ocean and Tauck could not be selected at all, and two renamed entries ("Atlas Ocean
  Voyages Cruises", "Quark Expeditions Cruises") pointed at names the catalogue no
  longer uses. The list is now regenerated daily from the live catalogue by CI rather
  than by hand. Ship owners and browse categories are still deliberately excluded —
  nobody books under "Scylla Cruises" — but the field now says so and names the retail
  brand that carries their sailings.
- **`sort` still defaults to `departure_date`,** and the README now says so and shows
  why: imminent departures are not staler than the catalogue average (25.0% vs 26.8%).
  Departure dates are heavily tied, and the feed now breaks those ties by freshness, so
  a short run leads with the most-recently-confirmed sailings rather than with whatever
  was inserted first — the first 25 rows went from 0% carrying a booking link and 96%
  stale to 40% and 0%. The README's new coverage table gives the real per-field numbers.
- `cabinCategory` and `includePast` are passed through to the feed.

### 1.4 — includes a breaking output change

Two fields the Actor added on top of the feed are **removed from every record**:
`portCount` and `itineraryPortsText`.

- **`portCount` was wrong, not merely redundant.** It was `len(itinerary)` — a
  count of itinerary ROWS — while the `port_count` sitting on the same record is
  the distinct ports the ship actually calls at, with days at sea and package
  flight/land/hotel days excluded. Two different numbers under two near-identical
  names: across 86,126 served records they agreed on only 4,122 of the 55,643
  where `port_count` is populated. A sample record carried `port_count: 3` and
  `portCount: 5` at once, and `portCount` also reported a confident `0` for
  sailings that publish no itinerary at all, where `port_count` correctly says
  `null`. Anyone who summed, filtered or charted the wrong one got a wrong answer
  with nothing to warn them. **Use `port_count`.** If you specifically want the
  number of itinerary rows — sea days and travel days included — it is
  `len(itinerary)`, and it is yours to compute rather than ours to name.
- **`itineraryPortsText`** was `" → ".join(...)` over `itinerary[].port`, which is
  in every record already. Rebuild it in one line if you display it.

`price_amount`, `price_currency`, `price_per_night`, `fares[]` and every other
field are unchanged. The dataset views were updated to match: **Overview** and
**Itineraries** now show `port_count` ("Ports of Call") in place of the removed
fields.

#### Also in 1.4

- **Picking a cruise line now returns the whole line.** Each source spelled a line
  its own way, and the dropdown could only offer one spelling — so choosing
  Carnival matched just the sailings stored as "Carnival Cruise Line Cruises",
  610 of 11,806, with no indication the rest existed. Line names are now
  canonicalized in the upstream feed and the dropdown lists the canonical names,
  so a line is one option covering all of its sailings. 18 of the 51 options were
  affected; 19 are renamed (e.g. "Royal Caribbean Cruises" -> "Royal Caribbean",
  "MSC Explora Journeys Cruises" -> "Explora Journeys"). Sub-brands stay separate:
  Viking's river/ocean/expedition fleets, Celebrity vs Celebrity River, and
  Explora vs MSC are each still their own option.

### 1.3

- Removed the "API base URL" input. The upstream data source is fixed; callers
  can no longer point the Actor at a different host (operators may still override
  it at deploy time via the `CRUISEFEED_API_BASE` env var). The optional `apiKey`
  input is unchanged.

- Surfaced the enriched feed fields in the dataset views: Overview now shows
  taxes & fees, onboard credit and sold-out; Itineraries shows sea days. Records
  already carried the full set (`ship_code`, `destination_code`, `sea_days`,
  `port_count`, `taxes_and_fees`, `taxes_currency`, `obc_amount`, `sold_out`,
  `booking_url`, `detail_url`, `image_url`) via pass-through.

- Every record is keyed by an opaque `id` (data providers are abstracted away);
  the `sources` input and per-source de-duplication were removed.

### 1.1

- Every record now includes the full per-cabin-class `fares` breakdown
  (interior/oceanview/balcony/suite) with availability, alongside the lead-in price.
- Reads the versioned upstream API (`/v1`) and authenticates with
  `Authorization: Bearer`.

### 1.0

- Initial release. Download normalized cruise inventory from 60+ cruise lines
  (ships, sailing dates, durations, ports, day-by-day itineraries and pricing)
  via a single normalized cruise data API. Filter by line, source, region, port,
  ship, dates, duration, price and trip type.
