Documentation

Airbnb Vrbo CLI

airbnb-pp-cli

Install

npx -y @mvanhorn/printing-press-library install airbnb

Installs the CLI binary and the agent skill for Claude Code, Codex, Cursor, Gemini CLI, Copilot, and more. Add --cli-only or --skill-only for one half. Requires Node.

Documentation

Skip the Airbnb platform fee. Find the host's direct booking site for any Airbnb listing.

Search Airbnb from the terminal, run cheapest on a listing to extract the host's brand, web-search for their direct booking site, and report the lowest of three prices side-by-side. Cross-platform match, price-drop watchlist, host portfolio analysis, and trip planning all built on a local store that compounds over time. Every scrape persists: airbnb_listing search/get, cheapest, compare, plan, and watch check write the listings they fetch into the local SQLite store, and record a dated price snapshot whenever a real price is scraped — so price history and wishlist diff accrue from normal use.

VRBO is currently disabled. VRBO's anti-bot protection (Akamai) blocks the scraper, and the previous fallback path returned hardcoded placeholder data with the queried city stamped on top — fake results labeled as if they were real. Every VRBO entry point now returns "vrbo is temporarily disabled — pending Akamai workaround". The VRBO source code stays in tree so re-enabling is a flag flip plus the Akamai workaround. Use this CLI for Airbnb work; expect VRBO to come back in a future release.

Renamed from airbnb-vrbo-pp-cli to airbnb-pp-cli. Existing users get an automatic one-time state migration on first run (the ~/.airbnb-vrbo-pp-cli directory is renamed in place to ~/.airbnb-pp-cli; the same applies to the SQLite cache under ~/.local/share). AIRBNB_VRBO_* env vars are still read but emit a deprecation warning; switch to AIRBNB_PP_*. The legacy paths will be dropped in a future release.

Created by @mvanhorn (Matt Van Horn). Contributors: @tmchow (Trevin Chow), @bobeglz (bobe).

Authentication

Public search and listing detail need no auth. Authenticated features (Airbnb wishlists, trip history) use cookie import via auth login --chrome. The web-search backend is pluggable: Parallel.ai (paid, best), DuckDuckGo HTML (free default), Brave Search API (free tier), or Tavily (free tier).

Quick Start

# Verify reachability and which search backend is active.
airbnb-pp-cli doctor

# Find listings on Airbnb.
airbnb-pp-cli airbnb search 'Lake Tahoe' --checkin 2026-05-16 --checkout 2026-05-19 --guests 4

# Same query, VRBO side.
airbnb-pp-cli vrbo search 'Lake Tahoe' --checkin 2026-05-16 --checkout 2026-05-19 --guests 4

# The headline command. Find the host's direct booking site and the cheapest of three sources.
airbnb-pp-cli cheapest 'https://www.airbnb.com/rooms/37124493?check_in=2026-05-16&check_out=2026-05-19'

# One call: search both platforms, find direct sites, return ranked-by-savings list.
airbnb-pp-cli plan 'Lake Tahoe' --checkin 2026-05-16 --checkout 2026-05-19 --guests 4 --budget 1500

Unique Features

These capabilities aren't available in any other tool for this API.

Host-direct arbitrage

  • cheapest — Given an Airbnb or VRBO listing URL, find the host's direct booking site and report the cheapest of three sources.

    When a user names an Airbnb/VRBO listing, this is the right tool to reach for. Returns a structured comparison of OTA fees vs direct booking with actionable URLs.

    airbnb-pp-cli cheapest 'https://www.airbnb.com/rooms/37124493?check_in=2026-05-16&check_out=2026-05-19' --agent
    
  • plan — Search Airbnb and VRBO in parallel for a city/dates/budget, then run cheapest on the top results, return a ranked-by-savings list.

    The agent-friendly trip planner. One call returns ranked results across both platforms with direct-booking URLs and savings amounts.

    airbnb-pp-cli plan 'Lake Tahoe' --checkin 2026-05-16 --checkout 2026-05-19 --guests 4 --budget 1500 --agent
    
  • compare — Side-by-side: OTA total (with cleaning + service + tax fees) vs direct booking total, with dollar and percent savings.

    Use when an agent needs to justify a booking recommendation with concrete savings numbers.

    airbnb-pp-cli compare 'https://www.airbnb.com/rooms/37124493' --checkin 2026-05-16 --checkout 2026-05-19 --json
    
  • find-twin — Reverse image search a listing's photos to find the same property on direct booking sites or alternate platforms.

    When host extraction fails (vague host name), reverse image search is the most reliable signal.

    airbnb-pp-cli find-twin 'https://www.airbnb.com/rooms/37124493' --json
    

Cross-platform

  • match — Given a listing on Airbnb (or VRBO), find the same property on the other platform via geocode + amenities + photo signal.

    Cross-platform price discrimination is real; the same condo can cost 15 percent less on VRBO. This finds it.

    airbnb-pp-cli match 'https://www.airbnb.com/rooms/37124493' --json
    

Local state that compounds

  • watch — Add saved listings to a watchlist with target prices; watch check re-scrapes each and records a dated price snapshot whenever a real price comes back; cron-friendly exit code 7 signals a genuine drop.

    Use when a user is shopping a specific listing and waiting for a price drop. Schedule watch check daily; act on exit code 7. A listing whose price is unavailable for the chosen dates is reported under no_price and never counts as a hit (no false exit 7). Subcommands: watch add, watch list, watch remove, watch check.

    airbnb-pp-cli watch add 'https://www.airbnb.com/rooms/37124493' --max-price 350 --checkin 2026-05-16 --checkout 2026-05-19
    airbnb-pp-cli watch remove 'https://www.airbnb.com/rooms/37124493'   # or: watch remove 37124493
    
  • host portfolio — Given a host or property management company name, list every known listing under them across Airbnb and VRBO.

    Discover bulk patterns: which PMCs operate in this city, which have direct sites, where to focus arbitrage.

    airbnb-pp-cli host portfolio 'Vacasa' --json --select listings.title,listings.location
    
  • wishlist diff — Track price changes on Airbnb wishlists over time; report which saved listings dropped, by how much, and over what window.

    User saved a listing months ago and forgot. This surfaces price movement so they can act before booking.

    airbnb-pp-cli wishlist diff --since 2026-04-01 --json
    
  • fingerprint — Stable hash from photos + amenities + host + city; used by match for dedupe; exposed for power-user export workflows.

    Build your own external joins on listings; stable across sessions.

    airbnb-pp-cli fingerprint 'https://www.airbnb.com/rooms/37124493'
    

Usage

Run airbnb-pp-cli --help for the full command reference and flag list.

Commands

airbnb_listing

Airbnb listings (search and detail) via SSR HTML scrape (openbnb pattern, no auth required).

  • airbnb-pp-cli airbnb_listing get - Get full Airbnb listing detail (amenities, house rules, location, highlights, description, policies, host) via SSR HTML scrape.
  • airbnb-pp-cli airbnb_listing search - Search Airbnb listings by location, dates, and guest count via the public SSR HTML page (openbnb pattern). Walks niobeClientData[0][1] Apollo cache to extract structured results.

airbnb_wishlist

Airbnb wishlists (read user's saved listings; requires auth login --chrome).

  • airbnb-pp-cli airbnb_wishlist items - Get items in a specific wishlist by listing IDs.
  • airbnb-pp-cli airbnb_wishlist list - List the user's wishlists via Airbnb's GraphQL persisted query.

host

Host identity extraction (the linchpin of host-direct arbitrage).

  • airbnb-pp-cli host extract - Extract the host's brand or display name from a listing URL across both platforms. Uses propertyManagement.name (PMC) > host.displayName > description bio > photo signal.
  • airbnb-pp-cli host portfolio - List every known listing under one host or PMC across Airbnb and VRBO from the local store.

vrbo_listing

VRBO listings (search and detail) via /graphql with Akamai warmup pattern.

  • airbnb-pp-cli vrbo_listing get - Get full VRBO property detail via the propertyDetail GraphQL operation (operation name discovered at runtime). Falls back to PLUGIN_STATE SSR scrape for basic fields.
  • airbnb-pp-cli vrbo_listing search - Search VRBO properties via the propertySearch GraphQL operation. Uses Akamai warmup (GET / first, wait 1.5s, then POST).

Output Formats

# Human-readable table (default in terminal, JSON when piped)
airbnb-pp-cli airbnb_listing get

# JSON for scripting and agents
airbnb-pp-cli airbnb_listing get --json

# Filter to specific fields
airbnb-pp-cli airbnb_listing get --json --select id,name,status

# Dry run — show the request without sending
airbnb-pp-cli airbnb_listing get --dry-run

# Agent mode — JSON + compact + no prompts in one flag
airbnb-pp-cli airbnb_listing get --agent

Agent Usage

This CLI is designed for AI agent consumption:

  • Non-interactive - never prompts, every input is a flag
  • Pipeable - --json output to stdout, errors to stderr
  • Filterable - --select id,name returns only fields you need
  • Previewable - --dry-run shows the request without sending
  • Read-only by default - this CLI does not create, update, delete, publish, send, or mutate remote resources
  • Offline-friendly - the search command and host portfolio/wishlist diff read from the local SQLite store; sync refreshes it by re-scraping what the store already knows
  • Agent-safe by default - no colors or formatting unless --human-friendly is set

Exit codes: 0 success, 2 usage error, 3 not found, 4 auth error, 5 API error, 7 rate limited, 10 config error.

Sync

Airbnb has no public paginated collection to mirror, so sync does not page a remote API. Instead, sync (with no --resources) re-scrapes what the store already knows — every watchlist entry (with its saved dates) and every previously-scraped listing — and persists a fresh dated price snapshot whenever a real price comes back. Seed the store first via watch add, airbnb_listing search/get, or cheapest; then schedule sync to keep price history current. When the store is empty, sync says so honestly (a sync_warning with reason empty_store) and makes no network calls.

The authenticated Airbnb wishlist sync is a separate, opt-in resource — it requires imported Chrome cookies and is never part of the default run:

airbnb-pp-cli auth login --chrome            # one-time: import cookies
airbnb-pp-cli sync --resources airbnb_wishlist   # auth-gated; without cookies this is an auth error, not a 404

The standalone wishlist sync command remains the other auth-gated path to pull wishlists; wishlist diff reports the price movement those snapshots accumulate.

Freshness

This CLI owns bounded freshness for registered store-backed read command paths. In --data-source auto mode, covered commands check the local SQLite store before serving results; stale or missing resources trigger a bounded refresh, and refresh failures fall back to the existing local data with a warning. --data-source local never refreshes, and --data-source live reads the API without mutating the local store.

Set AIRBNB_PP_NO_AUTO_REFRESH=1 to disable the pre-read freshness hook while preserving the selected data source.

Covered command paths:

  • airbnb-pp-cli airbnb_wishlist
  • airbnb-pp-cli airbnb_wishlist items
  • airbnb-pp-cli airbnb_wishlist list

JSON outputs that use the generated provenance envelope include freshness metadata at meta.freshness. This metadata describes the freshness decision for the covered command path; it does not claim full historical backfill or API-specific enrichment.

Health Check

airbnb-pp-cli doctor

Verifies configuration, credentials, and connectivity to the API.

Configuration

Config file: ~/.config/airbnb-pp-cli/config.toml

Troubleshooting

Authentication errors (exit code 4)

  • Run airbnb-pp-cli doctor to check credentials Not found errors (exit code 3)
  • Check the resource ID is correct
  • Run the list command to see available items

API-specific

  • VRBO returns 'Bot or Not?' challenge — The CLI uses Surf with Chrome TLS impersonation and a warmup pattern by default. If you still see challenges: run airbnb-pp-cli doctor --probe vrbo to verify the warmup is firing; reduce request rate with --rate 0.3 (req/sec).
  • cheapest returns 'no direct site found' — Try --search-backend parallel or --search-backend brave for higher-quality results; ensure PARALLEL_API_KEY or BRAVE_SEARCH_API_KEY is set in env.
  • Airbnb wishlist commands fail with auth error — Run airbnb-pp-cli auth login --chrome to import your Chrome cookies; airbnb-pp-cli auth status verifies.
  • watch check exits with code 7 — Code 7 means at least one watched listing scraped a real price at or below its threshold — that is the success path. It fires only on a genuine price drop. A listing whose price is unavailable for the chosen dates is reported under no_price (reason no_price_data) and never triggers exit 7. Check hits with airbnb-pp-cli watch list --since 24h.

Discovery Signals

This CLI was generated with browser-captured traffic analysis.

  • Target observed: https://a0.muscache.com/airbnb/static/packages/web/en/e67b.b1e4978dd5.js
  • Capture coverage: 66 API entries from 299 total network entries
  • Reachability: standard_http (65% confidence)
  • Protocols: rpc_envelope (80% confidence), rest_json (75% confidence)
  • Auth signals: api_key — headers: X-Airbnb-API-Key, X-Goog-Api-Key
  • Generation hints: has_rpc_envelope, weak_schema_confidence
  • Candidate command ideas: create_GetViewportInfo — Derived from observed POST /$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/GetViewportInfo traffic.; create_StaysPdpSections — Derived from observed POST /api/v3/StaysPdpSections/{hash} traffic.; create_get_data_layer_variables — Derived from observed POST /api/v2/get-data-layer-variables traffic.; create_js — Derived from observed POST /js/ traffic.; create_marketing_event_tracking — Derived from observed POST /api/v2/marketing_event_tracking traffic.; create_messages — Derived from observed POST /tracking/jitney/logging/messages traffic.; create_realtimeconversion — Derived from observed POST /track/realtimeconversion traffic.; get_GetConsentFlagsQuery — Derived from observed GET /api/v3/GetConsentFlagsQuery/{hash} traffic.

Warnings from discovery:

  • empty_payload: API-looking request returned an empty or null payload; schema confidence is weak.
  • empty_payload: API-looking request returned an empty or null payload; schema confidence is weak.
  • empty_payload: API-looking request returned an empty or null payload; schema confidence is weak.
  • empty_payload: API-looking request returned an empty or null payload; schema confidence is weak.
  • empty_payload: API-looking request returned an empty or null payload; schema confidence is weak.
  • empty_payload: API-looking request returned an empty or null payload; schema confidence is weak.
  • empty_payload: API-looking request returned an empty or null payload; schema confidence is weak.
  • empty_payload: API-looking request returned an empty or null payload; schema confidence is weak.
  • empty_payload: API-looking request returned an empty or null payload; schema confidence is weak.
  • empty_payload: API-looking request returned an empty or null payload; schema confidence is weak.

Sources & Inspiration

This CLI was built by studying these projects and resources:

Generated by CLI Printing Press

For agents: pass /documentation/airbnb/agents.md to install this CLI from a prompt.