TUI Scraper & Package Holiday Price Tracker - Pauschalreise
Pricing
from $1.40 / 1,000 package offers
TUI Scraper & Package Holiday Price Tracker - Pauschalreise
TUI scraper and package holiday price tracker: compare Pauschalreise offers across TUI, DERTOUR, weg.de, ab-in-den-urlaub.de and alltours in one dataset, with GIATA hotel matching, airport matrix, 90-day price history, buy-or-wait forecasts and price-drop alerts.
Pricing
from $1.40 / 1,000 package offers
Rating
0.0
(0)
Developer
Kamer Ozkan
Maintained by CommunityActor stats
0
Bookmarked
15
Total users
5
Monthly active users
2 days ago
Last modified
Categories
Share
Unofficial, independent price-monitoring tool. Not affiliated with, endorsed by, or sponsored by TUI, DERTOUR, weg.de, ab-in-den-urlaub.de, alltours, or any other travel provider.
Package holiday (Pauschalreise) price comparison and monitoring API for the German market: one search across TUI, DERTOUR, weg.de, ab-in-den-urlaub.de, and alltours returns normalized hotel + flight offers, same-hotel comparisons keyed by GIATA ID, departure-airport matrices, a deduplicated 90-day price history, market-availability signals, explainable buy-or-wait forecasts, and signed price-drop alerts to your webhook. Built for tour-operator pricing teams, OTAs, travel agencies, and travel-market analysts; it collects observations, not bookings.
What you can build with it
📉 1. A buy-or-wait desk for the destinations you sell
Schedule one run per day per destination with history, signals, and forecast switched on. The Actor keeps a deduplicated price series per stable package, scores availability narrowing from repeated observations, and emits an explainable buy_wait_forecast record (trend, volatility, days to departure, capacity evidence) instead of a black-box score.
{"destination": "Antalya","startDate": "8 weeks","endDate": "10 weeks","nights": 7,"adults": 2,"departureAirports": ["DUS"],"operators": ["tui", "dertour", "weg"],"outputMode": "comparisons","history": { "enabled": true, "storeName": "antalya-watch" },"signals": { "enabled": true },"forecast": { "enabled": true }}
🔔 2. Price-drop and capacity alerts to Slack, Make, or your CRM
Add alerts with up to five HTTPS webhooks. Deliveries are HMAC-signed, idempotent, cooldown-controlled (default 24 h per subject), and capped per run; only actually delivered alerts are billed. Alert types: price_drop, price_rise, availability_narrowing, source_recovery.
{"alerts": {"enabled": true,"webhookUrls": ["https://hooks.example.com/package-prices"],"types": ["price_drop", "availability_narrowing"],"priceChangePercent": 5,"cooldownHours": 24}}
🏨 3. Cheapest source for the same hotel, like for like
outputMode: "comparisons" returns one row per GIATA hotel with every source's cheapest offer side by side; comparisonMode: "like_for_like_package" additionally matches date, nights, occupancy, airport, room class, and board class, and matchQuality says per dimension what was matched exactly. Missing flight, baggage, transfer, or cancellation data stays explicit; nothing is invented.
✈️ 4. Departure-airport matrix for agencies and content teams
airportMatrix fans out one isolated search per requested airport (bounded by maxAirports, concurrency, and requestBudget) and emits comparable package prices by departure point, so a "from Düsseldorf vs. from Munich" table for the same hotel is one run.
Pricing and cost examples
Pay-per-event: the primary event is one normalized package offer; every optional layer has its own named event, so you pay only for the layers you switch on. Prices below are the FREE-tier rates effective 16 September 2026 (until 15 September 2026 the previous, lower rates on the pricing tab apply). Paid Apify plans get automatic tier discounts of up to 30%.
| Event | Price | What you get |
|---|---|---|
| 📦 Package offer (primary) | $0.002 | One normalized hotel + flight offer |
| 🔎 Successful source search | $0.015 | One source that returned results (failed searches are free) |
| 🧮 Comparison row | $0.002 | One GIATA hotel with all sources side by side |
| 🗂️ History update | $0.0005 | One new deduplicated observation in the 90-day series |
| ✈️ Airport-matrix row | $0.003 | One comparable price by departure airport |
| 📊 Market signal | $0.03 | One explainable availability-narrowing or price-jump signal |
| 📉 Buy-or-wait forecast | $0.03 | One explainable forecast record for a package series |
| 🔔 Alert delivered | $0.05 | One signed webhook delivery that actually reached your endpoint |
| 🧾 Detail enrichment | $0.004 | One evidence-backed offer-page lookup (cached) |
| ▶️ Actor start | $0.005 per GB | Once per run; the default 2 GB run is $0.01 |
Worked examples at the 16 September prices:
- One-off comparison, Antalya, 5 sources x 20 offers with comparison rows: ≈ $0.33
- Daily buy-or-wait desk, one destination, 3 sources, 10 offers, history + signals + forecasts: ≈ $0.40 per run → ≈ $12 per month
- Alerting: each delivered price-drop or capacity alert adds $0.05; a quiet day costs nothing extra
Set a maximum cost per run and read OUTPUT.billing before raising result or matrix limits; the Actor stops work before your cap is exceeded.
Related Actors
- HolidayCheck Reviews Scraper - German Hotel Ratings & Trends - guest reviews, aspect trends, and competitor sets for the hotels you price
- Trusted Shops & ProvenExpert Reviews Scraper - German Ratings - ratings of German travel agencies and providers
- Google Ads Transparency Center Scraper & Ad Change Monitor - what competing operators advertise, as a change feed
Why use it?
- Find the cheapest source for the same GIATA hotel with
dachEntityId. - Compare Düsseldorf, Munich, Frankfurt, or other departure airports.
- Build a deduplicated 90-day price curve for each stable package.
- Detect narrowing market availability from repeated observations.
- Create explainable buy/wait signals from price trend, volatility, days to departure, and availability evidence.
- Send optional signed webhook alerts with cooldown and retry protection.
- Keep partial results when one source is temporarily unavailable.
The Actor is built for tour-operator pricing teams, OTAs, travel agencies, and travel-market analysts. It collects observations, not bookings. A provider may revalidate price or availability at checkout.
Quick start
Use this minimum input:
{"destination": "Antalya","startDate": "8 weeks","endDate": "10 weeks","nights": 7,"adults": 2,"childAges": [],"departureAirports": ["DUS", "MUC"],"operators": ["tui", "dertour", "weg", "aidu", "alltours"],"outputMode": "comparisons","maxResultsPerOperator": 20}
Dates accept either an absolute YYYY-MM-DD value or a rolling relative value
such as 8 weeks. The Store form is prefilled with a valid rolling window so a
new user can run the example without repairing stale calendar dates.
Results are written to the default dataset. OUTPUT in the default key-value
store contains run status, record counts, source health, quality indicators,
errors, feature summaries, cost telemetry, and billing operations.
Input parameters
Required fields are destination, startDate, endDate, and departureAirports.
Everything else has a safe default, and every optional layer is off until you switch it on.
| Field | Default | What it does |
|---|---|---|
destination | Antalya | Country, region, or city, for example Mallorca, Hurghada, or Türkische Riviera |
startDate / endDate | form prefill 8 weeks / 10 weeks | Departure window as YYYY-MM-DD or a rolling value such as 8 weeks |
nights | 7 | Trip duration |
adults / childAges | 2 / [] | Occupancy; give each child's age on departure |
departureAirports | ["DUS"] | IATA codes such as DUS, MUC, FRA |
operators | all five | tui, dertour, weg, aidu (ab-in-den-urlaub.de), alltours |
outputMode | offers | offers (one row per source offer) or comparisons (one row per GIATA hotel) |
comparisonMode | lowest_offer_in_search_window | Or like_for_like_package for strict date, room, and board matching |
maxResultsPerOperator | 20 | Caps normalized offers per source |
sort | priceAsc | Price order or the source's recommendation order |
history, signals, forecast | off | 90-day price series, availability signals, buy-or-wait records |
airportMatrix | off | One bounded search per departure airport |
enrichment | off | Cached offer-page lookups for baggage, transfer, and cancellation evidence |
alerts, alertSigningSecret | off | Signed HTTPS webhooks with cooldown |
proxyConfiguration | no proxy | Optional Apify Proxy, used only for browser-backed retries |
API and integrations
Run it from your own code with the Apify API and read the dataset when the run finishes:
curl -X POST "https://api.apify.com/v2/acts/kamerozkan~dach-package-holiday-price-api/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"destination":"Mallorca","startDate":"6 weeks","endDate":"8 weeks","nights":7,"adults":2,"departureAirports":["FRA"],"outputMode":"comparisons"}'
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("kamerozkan/dach-package-holiday-price-api").call(run_input={"destination": "Hurghada","startDate": "8 weeks","endDate": "10 weeks","departureAirports": ["DUS", "MUC"],"outputMode": "comparisons",})for row in client.dataset(run["defaultDatasetId"]).iterate_items():print(row["recordType"], row.get("cheapestOperator"), row.get("cheapestTotalPrice"))
- Schedules: create an Apify schedule for a daily watch; turn on
historywith a fixedstoreNameso every run adds to the same price series. - Webhooks: use the built-in
alertsblock for signed price-drop messages, or an Apify run webhook to trigger Make, Zapier, n8n, or your own endpoint when a run succeeds. - Exports: download the dataset as JSON, CSV, or Excel, or pull it into Google Sheets.
- AI agents: the Actor is available through the Apify MCP server.
FAQ
Does it book trips or hold prices? No. It records public offers as observations. The provider may revalidate price and availability at checkout.
Which destinations work?
Any destination the selected German portals sell as a package holiday. The Actor resolves the name per source; use destinationOverrides only when a name is ambiguous.
Why did one source return nothing?
Each source is searched separately. A source without matching offers or with a temporary error is reported in OUTPUT and in a run_diagnostic row, and failed source searches are not charged. The other sources still deliver.
How do I compare the same hotel across portals?
Set outputMode to comparisons. Rows are keyed by GIATA hotel ID (dachEntityId), so the same hotel lines up across sources.
How do I keep costs predictable?
Keep maxResultsPerOperator small, switch on only the layers you need, and set a maximum cost per run. The Actor stops before the cap is exceeded.
Are prices per person or per booking?
Both, when the source publishes them: price.total is the full package and price.perPerson is filled when available. Missing values stay null.
Live sources and evidence
| Source | Transport | Hotel identity | Notable evidence |
|---|---|---|---|
| TUI Germany | Direct JSON | GIATA | Price, date, duration, room, board, discount |
| DERTOUR Germany | Direct JSON | GIATA | Flight legs, transfer, availability, flex marker |
| weg.de | Browser + intercepted JSON | GIATA | Flight, transfer, deal/flex markers, old price |
| ab-in-den-urlaub.de | Direct JSON | GIATA | Price, room/board, flex text; cashback is separate |
| alltours | Persisted GraphQL | GIATA | Flight, package operator, free cancellation, old price |
Missing flight, baggage, transfer, cancellation, tax, or fee data remains explicit. The Actor does not invent unavailable fields. Optional, bounded weg.de detail enrichment can fill evidence-backed baggage, transfer, and flexible-cancellation fields and uses a persistent positive/negative TTL cache.
Comparison modes
lowest_offer_in_search_windowcompares the cheapest hotel offer returned by every selected source.like_for_like_packageadditionally matches departure date, nights, occupancy, airport, normalized room class, and normalized board class.
Match-quality fields label exact, normalized, requested, mixed, and missing dimensions so downstream systems can decide what is comparable.
Dataset record types
offercomparisonairport_matrixprice_seriesmarket_signalbuy_wait_forecastalert_deliveryrun_diagnostic- emitted without a result charge when no primary rows can be written, so an empty search, partial source outage, and spending limit are immediately distinguishable.
Real records from live runs
The two records below are unedited engine output from live runs on 2026-07-28; only image lists and one very long source ID are shortened.
A real cross-operator comparison: the same GIATA-identified hotel, like-for-like
window, three portals, and a real 27 EUR spread. matchQuality declares per dimension
what was matched exactly and what was normalized, so a like-for-like claim is auditable
instead of asserted:
A full offer record, including both flight legs as sold. Price honesty is structural:
originalTotal, savingPercent, and taxesIncluded stay null when the portal does
not publish them, and price.completeness says so explicitly. Hotel reputation fields
are passed through as the source states them, even when they are unflattering (this
2-star property shows its single review and 0 percent recommendation as-is):
The full input is in examples/INPUT.json, a recurring watch is in
examples/SCHEDULED_WATCH.json, and a normalized output sample is in
examples/OUTPUT_OFFER.json.
Reliability and limits
- Each source has typed errors, bounded retries, health summaries, and circuit breaking.
- Airport matrix fan-out has explicit airport, concurrency, and request limits.
- Explicit source-airport fallbacks are discarded when they do not match any requested IATA code, and the mismatch is reported in run diagnostics.
- Price history is sharded, deduplicated, retained for 90 days by default, and stable across transient offer or flight identifiers.
- Capacity scoring requires repeated observations and is suppressed when source coverage drops. It estimates market availability, not hotel occupancy.
- Forecasts are informational signals, not price or booking guarantees.
- HTTPS webhooks support HMAC signatures, idempotency keys, cooldowns, bounded retries, redirect blocking, and target-URL redaction.
alertSigningSecretis a top-level encrypted input and is mapped into the webhook runtime configuration without being emitted.- Pay-per-event guardrails stop work and output before the caller's maximum charge is exceeded.
The Store input defaults to proxy-free access. WEG tries direct browser access first and uses a configured Apify Proxy only on retry. Direct supplier API requests stay off the proxy; their browser fallbacks activate only when a direct source response is blocked or empty. Source APIs and persisted-query hashes can change; source-specific schema drift is reported without discarding successful sources.
Pricing
See "Pricing and cost examples" at the top of this page for the full event table and worked examples. Failed source searches, failed webhooks, cooldown-suppressed alerts, and duplicate history observations are never charged as successful events. Review the Store pricing tab, set a maximum cost per run, and inspect OUTPUT.billing before increasing result or airport-matrix limits.
This Actor is also exposed to AI agents through Apify's MCP server (mcp.apify.com): an agent can discover it by search and run it with the same pay-per-event billing, with no separate integration.
Privacy and lawful use
The Actor does not require traveller names, email addresses, payment details, or booking personal data. Child ages are optional search parameters. Webhook URLs and signing secrets remain within the caller's input and storage.
Users are responsible for lawful, proportionate use and compliance with applicable website terms, robots policies, database rights, privacy law, and contractual restrictions. Do not use the Actor to bypass access controls or overload source systems.
Support and feedback
- Found a bug or missing a field? Open an issue on the Issues tab of this Actor. We reply within 48 hours and ship most fixes within a few days.
- Have an idea for a feature? Issues are the fastest way to get it built.
- If the Actor saves you time, a short review on this page helps other users find it.
Support and versioning
For reproducible schema drift or source failures, include the run ID, redacted input, affected source, and first error code. Upstream website changes are supported on a best-effort basis unless a separate SLA exists.
Breaking output changes use a major version; additive fields use a minor
version; source fixes use a patch version. See CHANGELOG.md for release
history.
Local development
Node.js 22.19 or newer is required.
npm installnpm run release:preflightnpm run release:live
For a local Apify run, place input at
storage/key_value_stores/default/INPUT.json, then run:
$CRAWLEE_STORAGE_DIR="$PWD/storage" npm start
Price and date integrity maintenance, October 4, 2026
Required negative or nonfinite source totals are rejected by all five adapters and the comparison gate. Negative optional monetary values remain unknown; legitimate zero amounts are preserved. Provided source dates must be real Gregorian dates, and return-before-departure records are rejected. Missing dates stay unknown, with no requested-date substitution. Ninety-two focused offline cases and seventeen independent control groups passed with no source requests. Existing healthy normalized contracts match the prior version. This verification does not prove current provider access, availability, booking eligibility or customer revenue. Network access, dependency versions, input schema and pricing are unchanged.