Cache and Price Freshness in Metasearch

Design travel-metasearch caching with realistic search load, adaptive TTLs, selective live rechecks, stale-price risk, observability and production trade-offs.

Editorial information
Advertisement

Caching in travel metasearch is not simply a question of “how many minutes should a price live?” The real design problem is balancing latency, supplier cost, coverage and traveler trust. Calling every provider live for every search can be slow and expensive; keeping offers too long can create stale rates and sold-out clicks.

Consider a system with 150,000 hotels, six suppliers and hundreds of searches per second. Fan-out live calls can push p95 latency into multiple seconds and consume upstream quotas. A fixed 30-minute cache may improve speed while producing unacceptable mismatch rates for near-term, volatile inventory. The useful solution is usually a context-aware freshness policy, not one global TTL.

Why is price freshness a product requirement?

Freshness directly affects trust and conversion. If the result page shows €120 and the provider landing page shows €137, a technically successful cache hit has produced a poor product outcome.

Freshness can be thought about in three layers:

  • technical freshness: how old is the observation?
  • commercial freshness: is the amount still valid?
  • transactional freshness: can the traveler still obtain the same offer now?

Cache age alone cannot answer all three. Two prices with the same age can have very different volatility.

How should indicative and live prices be separated?

Indicative pricing is useful for exploration; live pricing is more appropriate as the user approaches transaction intent. Skyscanner explicitly distinguishes indicative cached data from live pricing use cases, while Google Hotels documents cached pricing and live pricing queries.

Keep source semantics in the internal model:

ts
type PriceSource = "indicative" | "cached-live" | "live";

interface PriceObservation {
  providerId: string;
  propertyId: string;
  itineraryKey: string;

  amount: number;
  currency: string;

  observedAt: string;
  expiresAt: string;
  source: PriceSource;

  roomId?: string;
  ratePlanId?: string;
  availabilityCheckedAt?: string;

  confidence: number;
}

Even if ranking and UI ultimately display one number, the backend should not erase how that number was obtained.

How should the cache key be designed?

A bad cache key can be more dangerous than a long TTL. Caching by property ID alone is insufficient for hotel pricing.

A useful key commonly includes:

text
provider
+ property
+ check-in
+ nights
+ occupancy
+ room count
+ market
+ currency
+ eligibility/rate-rule context

If child ages, member rates or country-specific rules affect pricing, those dimensions may also need to be represented.

Otherwise a cache “hit” may belong to another traveler's commercial context.

Why is one global TTL too simplistic?

Volatility varies by offer. A hotel for tomorrow with limited remaining inventory behaves differently from the same property six months out.

Adaptive TTL can incorporate:

  • check-in proximity,
  • historical mismatch rate,
  • historical price-change frequency,
  • supplier,
  • property popularity,
  • search/click volume,
  • remaining-inventory signals,
  • events/holidays,
  • booking window,
  • promotions.

Example policy:

text
check-in <= 2 days       => base TTL 2 min
check-in <= 7 days       => base TTL 5 min
check-in <= 30 days      => base TTL 15 min
check-in > 30 days       => base TTL 60 min

provider mismatch > 5%   => TTL x 0.50
high click volume        => refresh priority +2
high sold-out risk       => TTL x 0.50
stable supplier/property => TTL x 1.50

These values are not universal. They should be calibrated using first-party mismatch, conversion and supplier-latency data.

How should refresh priority work?

Large catalogs cannot refresh every key equally. Freshness therefore becomes a scheduling problem as well as a TTL problem.

A simple priority model could be:

text
priority =
  search_volume_weight
+ click_volume_weight
+ checkin_proximity_weight
+ mismatch_history_weight
+ revenue_weight
- recent_refresh_penalty

Workers can refresh the highest-value contexts first. This is often more efficient than attempting to keep every long-tail itinerary equally fresh.

Where does stale-while-revalidate make sense?

Browse and inspiration experiences may safely show a recent cached value while refreshing asynchronously. Transaction-oriented moments need stricter rules.

For example:

text
Destination page       -> indicative/cached acceptable
Search result          -> fresh cached preferred
Offer detail           -> stricter freshness
Provider click         -> optional live recheck
Booking ownership      -> transaction-time validation

Using one policy across the entire funnel ignores user intent.

When should click-time live revalidation happen?

Revalidating every click increases latency and supplier cost. It can be selectively triggered when:

  • check-in is close,
  • provider mismatch history is poor,
  • cached age exceeds a threshold,
  • booking value is high,
  • inventory looks constrained,
  • the offer is promotional or conditional.

The product must also define what happens when revalidation returns a different price:

  1. show the new amount,
  2. re-rank the offer,
  3. show alternatives,
  4. block handoff for severe mismatch.

Silently redirecting after a material price change is itself a product decision and should not happen accidentally.

What failure modes matter?

Cache stampede

A popular key expires and hundreds of requests hit the same supplier. Use single-flight, locking or background refresh.

Poisoned cache

An incorrectly normalized occupancy or tax rule is cached and amplified by a high hit rate.

Stale data during provider outage

Using stale cache during an outage can preserve coverage but increase trust risk. Stale-if-error needs explicit thresholds.

Timestamp errors

Timezone or provider-timestamp mistakes can make old data appear fresh.

Silent fallback

A live request times out and cached data is returned without recording the fallback. Dashboards then overstate live coverage.

Hot-key starvation

Priority refresh keeps popular properties fresh while long-tail inventory ages indefinitely. Introduce minimum coverage or fairness rules.

How should mismatch feedback affect caching?

Mismatch should modify future behavior, not just populate a report.

A useful loop is:

text
Displayed cached price
        |
        v
Provider landing check
        |
        +--> matched
        |      |
        |      +--> confidence up
        |
        +--> mismatch
               |
               +--> classify reason
               +--> volatility up
               +--> effective TTL down
               +--> refresh priority up

Google's price-accuracy resources include mismatch reasons such as tax mismatch, room unavailable, delayed price feed and wrong itinerary, illustrating why a reason taxonomy is more actionable than one global mismatch percentage.

Which metrics should be monitored?

Cache health

  • cache hit ratio,
  • miss ratio,
  • stale-while-revalidate use,
  • refresh queue depth,
  • refresh age p50/p95,
  • hot-key rate.

Freshness

  • offer age p50/p95,
  • live/cached/indicative ratio,
  • threshold-overrun rate,
  • provider/property freshness distribution.

Business quality

  • price mismatch rate,
  • unavailable-after-click,
  • mismatch by cache-age bucket,
  • conversion by freshness bucket,
  • revenue by freshness bucket,
  • click abandonment after reprice.

Supplier cost

  • live requests per search,
  • API quota usage,
  • provider timeout rate,
  • refresh cost per successful booking.

Do not optimize hit ratio in isolation. A 95% hit rate with a 12% mismatch rate may be a bad system.

What are the trade-offs?

PolicyLatencySupplier costFreshness risk
Always liveHighHighLow
Long fixed TTLLowLowHigh
Adaptive cache + selective liveMedium/LowMediumControlled

The adaptive approach is often attractive, but it adds complexity. It only works when observability exists; a system cannot tune for volatility it does not measure.

When should caching be avoided?

A live-first approach can be appropriate when:

  • supplier responses are fast and cheap,
  • inventory is extremely scarce,
  • offer tokens are very short-lived,
  • you own the booking transaction,
  • contracts or regulation require transaction-time validation.

Conversely, inspiration and broad-date discovery often do not justify full-live architecture.

Production checklist

  • Does the cache key represent the full commercial search context?
  • Does every price carry observedAt and source?
  • Are live and indicative observations distinct?
  • Can TTL adapt by provider and check-in proximity?
  • Is cache-stampede protection in place?
  • Is stale-if-error policy explicit?
  • Is live-to-cache fallback observable?
  • Are click-time validation triggers documented?
  • Do mismatch reasons feed future policy?
  • Is conversion measured by freshness bucket?
  • Is long-tail starvation controlled?
  • Can supplier cost and traveler trust be reviewed together?

Meta Search takeaway

Good cache design does not maximize hit ratio. It delivers sufficiently fresh offers for the current user intent at acceptable latency and supplier cost. When freshness metadata, adaptive TTL, priority refresh and mismatch feedback work together, caching becomes a product-quality mechanism rather than just an infrastructure optimization.

Technical advisory

Are you facing this in production?

We can review the symptom, data flow and integration behavior technically.

Discuss your project →

Sources

Related content

architecture

Cache Invalidation Patterns for Travel Pricing

Design TTL, event invalidation, stale-while-revalidate and live-reprice boundaries for hotel and flight pricing.

cachepricingfreshness
Explore →
architecture

Push vs Pull vs Hybrid for Travel Distribution

Compare push, pull and hybrid distribution models across freshness, latency, rate limits, caching, reconciliation and operational ownership.

pushpullhybrid
Explore →
architecture

Supplier Latency and Timeout Budgets in Metasearch

Design timeout budgets, parallel supplier calls, partial-result handling, circuit breakers and latency SLOs for hotel and flight metasearch search pipelines.

latencytimeoutsupplier
Explore →
travel-ecosystem

Juniper Travel Technology: Booking Engine and Distribution API Profile

ejuniper.com

A technical ecosystem profile of Juniper across travel booking engines, multi-product APIs, supplier connectivity and B2B distribution.

junipertravel-apibooking-engine
Explore →
travel-ecosystem

RoomCloud: Channel Manager and Metasearch Connectivity Profile

roomcloud.net

A technical profile of RoomCloud across real-time hotel distribution, PMS integrations, reservation delivery and metasearch connectivity.

roomcloudchannel-managermetasearch
Explore →
reports

Turkey Metasearch Market: Public-Evidence Technical Map 2026

Map Turkey's travel metasearch and distribution ecosystem across OTA, metasearch, GDS, NDC, bedbank, channel-manager, CRS and booking layers using public evidence.

turkeymetasearchtravel-distribution
Explore →