This is a step-by-step walkthrough of how to build a base-price dynamic pricing model for a short-term rental — the kind that produces a full calendar of nightly prices that move with the market. It covers what data you need, how to acquire it, how to shape it, and how to turn it into a price for every future date. We built on the mechanics described in How base-price models work; here the focus is entirely on how to do it.

You can build the whole thing in a spreadsheet, or as a small script if you want it to run on a schedule. We’ll note both as we go.

Step 1: Get the market data

The model runs on one input: pricing and availability data for the short-term rentals in your market. For each property, for each future calendar date, you want at minimum the nightly price and whether that night is available or booked. Useful additional fields are bedrooms, property type, guest capacity, location, and a stable listing ID so you can track the same property across collections.

There are two ways to get this data: buy it, or collect it yourself.

Option A — Buy it from a data provider

Companies such as AirDNA and Key Data already collect short-term rental market data at scale and sell access to it. You pick your market and receive pricing and availability data — often already aggregated to the market level — without doing any collection yourself. This is the fastest path and avoids the engineering and ongoing maintenance of running your own collection. The trade-off is cost, and that you inherit the provider’s definitions of “market” and “average” rather than controlling them yourself.

Option B — Collect it yourself (full walkthrough)

Collecting the data means programmatically reading, from the OTAs, the same prices and availability you could in principle gather by hand. Here is the whole pipeline.

  1. Build your seed list of listings. You need the set of listing URLs or IDs you want to track in your market. You can assemble this by querying an OTA’s search results for your area and paginating through them, recording each listing’s ID. Search results are paginated (Airbnb, for example, returns results in pages of ~18–20), so you loop: request a page, parse out the listing IDs, advance the offset/cursor, and continue until the area is exhausted. Store the resulting list of unique listing IDs — this is your collection target.
  2. Find the data endpoints rather than scraping rendered HTML. OTA pages are JavaScript apps that fetch their data from internal JSON/GraphQL APIs and render it client-side. Scraping the visible HTML is brittle; it’s far more reliable to call the same JSON endpoints the page calls. Open a listing in your browser with the network inspector running, watch the XHR/fetch requests, and identify the calls that return (a) the pricing/quote for a date range and (b) the availability calendar. Note the URL pattern, the query parameters (listing ID, check-in, check-out, guest count, currency), and any required headers or API keys the front end sends. You’ll replicate those calls in code.
  3. Pull each listing’s calendar and prices. For each listing ID, call the availability-calendar endpoint to get, per future date, whether the night is available and any per-night price it exposes. Where a calendar endpoint doesn’t return a usable nightly price, get the price from the quote/pricing endpoint by requesting a short stay (e.g. a one- or two-night range) for each date and reading the nightly rate back out. Be deliberate about parameters that change price — guest count, length of stay, and currency — and hold them constant across listings so you’re comparing like with like. Plan your horizon (e.g. the next 365 days) and iterate dates across it.
  4. Use a tool stack that can handle scale and blocking. A typical stack is Python with requests or httpx for the calls and asyncio/a task queue for concurrency, writing results to a database. At any real volume the OTAs will rate-limit or block raw requests, so production collection usually routes through a rotating residential/proxy pool (Bright Data, Oxylabs, and similar) or a managed scraping API that handles proxies, retries, and browser fingerprints for you. Add randomized delays, exponential-backoff retries, and respect HTTP 429s. If a specific flow only renders behind JavaScript, a headless browser (Playwright or Puppeteer) can drive it, though direct JSON calls are cheaper and faster where available.
  5. Store every reading as a time-stamped record. Write one row per (listing_id, stay_date) capture, including the price, the availability flag, the parameters you used (guests, length of stay, currency), and the collection timestamp. A simple relational schema — a listings table (id, bedrooms, type, capacity, location) joined to a prices table (listing_id, stay_date, price, is_available, collected_at) — is enough. Keeping the collection timestamp is what later lets the model be dynamic: you can see how the market repriced a given date between one run and the next.
  6. Schedule it to repeat. Run the whole collection on a fixed cadence — daily is common — with a cron job, a scheduled cloud function, or a workflow runner (Airflow, etc.). Each run appends a fresh snapshot, so over time you accumulate a moving picture of the market.

The output of one pass is a large table: one row per (listing, future-date) with a price, an availability flag, and a timestamp.

Defining your market

However you obtain the data, you have to decide which listings count as “the market” for a given property. This is the comp set, and there are two broad ways to draw the boundary.

The first is geography only: every listing within a city, defined area, or radius goes in. This is the simplest rule, gives you the largest number of observations, and produces the smoothest market curve — at the cost of mixing in properties that aren’t much like yours (studios alongside five-bedroom houses).

The second is a filtered comp set: you narrow the pool to properties similar to the one you’re pricing — for instance the same bedroom band, the same property type (entire home vs. private room), and a comparable guest capacity, within the same area. This tracks properties closer to yours, but with fewer observations the curve can be noisier and you may need a wider geography to compensate.

Neither is automatically correct; the choice is a trade-off between how representative the comp set is and how stable the resulting curve is.

Step 2: Build a single market price curve

After Step 1 you have many observations for each future date — potentially hundreds or thousands of listings priced for, say, the third Saturday in August. The model needs to collapse those into one market price per date.

For each future calendar date:

  • Gather every listed price for that date across your comp set — both available and booked nights, using the price each listing shows for that night.
  • Take the mean of those prices. With a large comp set the mean is a stable estimate of where the market sits, and it responds proportionally when listings reprice. Its weakness is sensitivity to outliers — a handful of luxury or mispriced listings can pull it around — so if your comp set is small or mixed, use the median instead (or trim the extremes before averaging). Either way, more observations mean a steadier curve, which is why bigger comp sets help.

Do this for every date in your horizon (commonly 365+ days out) and you have a market price curve: one representative market price for each future date. Plotted, it has peaks on weekends, higher plateaus in high seasons, and spikes on holidays and events — because that’s how the underlying listings are priced.

Step 3: Convert the curve to percentage factors

The market price curve is in dollars, and your property isn’t priced like the market average. So you convert the curve’s shape — its ups and downs — into percentages, which can then be applied to any base price.

  • Compute the reference price: the average of the entire curve. Add up the market price for every future date and divide by the number of dates. Say that average across all future dates comes out to $213.
  • For each date, divide that date’s market price by the reference price. This gives a multiplier — a “factor.” A date priced at $251 against a $213 reference is 251 ÷ 213 ≈ 1.18 (+18%). A date at $187 is 187 ÷ 213 ≈ 0.88 (−12%). A holiday at $470 is 470 ÷ 213 ≈ 2.21 (+121%).

The result is a factor for every future date. Charted, it’s the exact same shape as the market price curve — it just reads in multiples of the average instead of dollars. Each factor says how far above or below the year’s average the market sits on that date.

Step 4: Choose a base price and generate your prices

Now you set a base price for your specific property — your estimate of what it should earn on an average night. For a 3-bedroom in Atlanta you might set $300.

For each future date, multiply your base price by that date’s factor:

  • A date with a factor of 1.18: $300 × 1.18 = $354
  • A date with a factor of 0.88: $300 × 0.88 = $264
  • A date with a factor of 2.21: $300 × 2.21 = $663

Do this across the whole horizon and you have a complete calendar of nightly prices for your property.

You can optionally apply finishing rules at this stage: round to whole dollars, set a price floor and ceiling so no date can go below or above a chosen bound, and run different base prices for different listings while sharing the same market factors. These are conveniences layered on top of the multiplication, not part of the core calculation.

Step 5: Make it update over time

Run once, the model produces a single calendar and stops. It becomes dynamic when you re-run it on a schedule. Each time you collect a fresh snapshot, your comp set’s latest prices flow through Steps 2–4, the market curve and factors update, and your property’s prices move with them. A daily cadence is common. Day-to-day moves are usually small, because each date’s market price is an average over many listings and one property changing its rate barely moves it.

To automate this, the spreadsheet version becomes a script: a scheduled job that (a) pulls a fresh snapshot, (b) rebuilds the market curve, (c) recomputes the factors, and (d) writes the new prices — optionally pushing them straight to your channel manager or PMS through its API.

How pricing tools present the result

If you’ve used a commercial pricing tool, you’ve seen a nightly price presented as a stack of adjustments:

  • Base $220
  • Seasonality +$27
  • Day of week +$35
  • Local demand +$25
  • Event +$30
  • Adjusted price $337

It’s worth being clear about what this is. The model did not compute the price by adding those components together. The price came out of the multiplication in Step 4 — base price × that date’s market factor. The breakdown is produced afterwards, by back-calculating how much of the total adjustment can be attributed to each recognizable effect. It’s an explanation layer, not the calculation.

You can build the same attribution from the factors you already have. The total adjustment for a date is base × (factor − 1) — in the example above, $117 on a $220 base, i.e. a factor of about 1.53. To split it:

  • Seasonality. Average the factors across the date’s month or season. If August averages 1.12, the seasonal effect is base × 0.12 = +$27, roughly.
  • Day of week. Within that season, compare the date’s weekday to the seasonal average — if Saturdays run about 16% above the August norm, that’s base × 1.12 × 0.16 ≈ +$35 on top.
  • The residual. Whatever remains of the gap between those layered effects and the date’s actual factor gets labeled as event or demand effects — “local demand,” “search demand,” and similar. By construction the lines always sum exactly to the predicted price, because the residual absorbs whatever the named effects don’t explain.

Done this way, the decomposition is honest about its own ordering: each line is conditional on the ones above it, and the labels on the residual are interpretive. Two tools could show different breakdowns of the identical price and both be internally consistent.

The presentation earns its place anyway. A bare $337 invites the question “why?”; the stack answers it in terms a host already understands — it’s August, it’s a Saturday, something is happening in town. Just read it as an explanation of a market-derived price, not as the model’s actual arithmetic.

Conclusion: should you build your own?

Having walked through every step, the honest answer for most people is no — for two reasons.

First, the build-versus-buy math doesn’t favor building. Everything described here already exists as a product, from dynamic pricing tools to full revenue management platforms, with PMS and channel-manager integrations, maintained data pipelines, and support. The hard parts of this walkthrough — reliable data collection at scale, fighting rate limits and changing endpoints, keeping the pipeline running every day — are exactly the parts that never stop costing you effort. Building your own means taking on all of that ongoing work to reproduce something you could simply connect to, and the end result is rarely better than what you’d have bought.

Second, and more fundamentally, a base price model is not revenue maximizing. Everything in this model flows from one source: what other listings are charging. It tracks the market’s shape faithfully, but it has no concept of demand for your property — no booking pace, no occupancy feedback, no measure of how demand responds to price. It cannot tell you the revenue-maximizing price for a night; it can only tell you where the market average sits and move you with it. If the whole market underprices a high-demand weekend, your model underprices it too. Squeezing the most revenue out of a calendar requires modeling demand directly — how likely a night is to book at a given price — and that’s a different class of model entirely.

So treat the base price model for what it is: an excellent way to understand how market-following pricing works, and a respectable baseline. But if your goal is maximum revenue rather than market parity, use a tool built for that — see how optimization models work — and let someone else maintain the scrapers.

Try it yourself: a working example

Reading through the steps is one thing; watching the numbers move is another. We’ve built a fully working version of this model as a Google Sheet, so you can look inside every calculation and change the inputs yourself. It follows the same four steps as this walkthrough: sample market data you can swap for your own, the market curve and factors computed from it, a price calendar driven by a single base-price cell, and the back-calculated price breakdown for any date you pick.

Every number downstream is a live formula, so changing the base price — or any input — recalculates the whole calendar instantly. To make it your own, open the sheet and choose File → Make a copy, then start experimenting.

Open the interactive base-price model →