Popular carsMarket dataSEOREST API

See what sold near you in the last 90 days, then stock and write for it

Turn MarketCheck's 90-day sales rankings into a popular-near-you widget and state pages, then use the monthly changes for stocking calls and an SEO content calendar.

MarketCheck5 min read

For developers and marketers at dealer groups, car-shopping sites and publishers

Popular Cars, GET /v2/popular/cars, answers one question: which make and model combinations sold the most units over the last 90 days, nationally, in a state or in a city. You choose new or used. The answer is a ranked list with price, mileage and days-on-market statistics for each model, and MarketCheck regenerates it monthly.

Because each list changes once a month, one call per market per refresh keeps it current. That makes it an easy input for shopper-facing pages and for two internal jobs, stocking and content planning.

In short. Call /v2/popular/cars with car_type and either state or city_state. Cache the list, because it is regenerated monthly. Show it to shoppers, and save each month's list so stocking and content planning can work from the changes.

What the endpoint returns

Besides your api_key, the request takes four parameters: car_type (required, new or used), state, city_state (a city and state joined with a pipe, such as the docs' jacksonville|FL) and country (us by default, or ca). With no location you get the national list. The docs cap state and national lists at 50 models and city lists at 25, sorted by count from highest to lowest.

Here are the first two entries, trimmed from the documented sample for new cars nationally:

Response (trimmed)json
[
  {
    "country": "us",
    "count": 155708,
    "make": "Toyota",
    "model": "RAV4",
    "price_stats": { "median": 36773, "trimmed_mean": 37070, "max": 111777, "listings_count": 150208 },
    "miles_stats": { "median": 5, "listings_count": 40032 },
    "dom_stats": { "median": 25, "listings_count": 155708 }
  },
  {
    "country": "us",
    "count": 124224,
    "make": "Toyota",
    "model": "Camry",
    "price_stats": { "median": 34199, "listings_count": 120498 },
    "dom_stats": { "median": 24, "listings_count": 124224 }
  }
]
  • count is the number of vehicles of that make and model sold in the window. The ranking follows it.
  • price_stats, miles_stats and dom_stats each carry a full set of statistics (median, mean, trimmed mean, IQR and more) plus their own listings_count. In the sample, far fewer new RAV4 listings carried a mileage than a price, so read each block's count before you quote it.
  • Prices are listed prices. price_stats describes what the cars were listed at. Show the median or the trimmed mean: in the sample the highest listed price sits far above the median, which is enough to pull a plain mean off.
  • The unit is make and model. The response has no trim or model year, so a ranking names the RAV4 without saying which trim or year.
  1. Shopper's city and state
  2. Popular Cars for the city
  3. Weekly cache
  4. Widget on your pages

A car-shopping site or dealer site can show "most popular used cars in your city" on its home page or search results, with the median listed price and median days on market next to each model. The city list is the most local answer the endpoint gives. When a city has no list, fall back to its state.

Match the list to the page. New-car pages and OEM model pages get the car_type=new list, and used-car search gets car_type=used, since the two rank different markets. Label the widget with its basis, such as "most sold in the last 90 days", so shoppers know the ranking comes from sales.

The same cached list can also badge your own inventory. A unit whose make and model appear in the city list can carry a "popular in your area" tag on its search card and detail page, with no extra calls once the list is in the cache.

popular.tsts
const BASE = 'https://api.marketcheck.com/v2'
const WEEK_MS = 7 * 24 * 60 * 60 * 1000

interface Stats { median: number, listings_count: number }
interface PopularCar { country: string, count: number, make: string, model: string, price_stats?: Stats, miles_stats?: Stats, dom_stats?: Stats }

async function popular(params: Record<string, string>): Promise<PopularCar[]> {
  const url = new URL(`${BASE}/popular/cars`)
  url.searchParams.set('api_key', process.env.MARKETCHECK_API_KEY ?? '')
  for (const [key, value] of Object.entries(params)) url.searchParams.set(key, value)
  const res = await fetch(url)
  if (!res.ok) throw new Error(`popular/cars returned ${res.status}`)
  return res.json()
}

// Lists are regenerated monthly, so a weekly refresh picks up each new one within days
const cache = new Map<string, { at: number, cars: PopularCar[] }>()

async function rankings(city: string, state: string, carType: 'new' | 'used') {
  const key = `${carType}:${city}|${state}`
  const hit = cache.get(key)
  if (hit && Date.now() - hit.at < WEEK_MS) return hit.cars
  // Send city_state or state, never both: city_state wins when both are present
  let cars = await popular({ car_type: carType, city_state: `${city}|${state}` })
  if (!cars.length) cars = await popular({ car_type: carType, state })
  cache.set(key, { at: Date.now(), cars })
  return cars
}

export async function popularNear(city: string, state: string, carType: 'new' | 'used', limit = 10) {
  const cars = await rankings(city, state, carType)
  return cars.slice(0, limit).map((car, i) => ({
    rank: i + 1,
    name: `${car.make} ${car.model}`,
    medianListedPrice: car.price_stats?.median,
    medianDaysOnMarket: car.dom_stats?.median
  }))
}

State pages follow the same pattern. A page titled for the most popular used cars in a state can render the state list with each model's median listed price and median days on market, and link each model to your inventory search. Regenerate the page when the list changes, and date it, so the page says which 90 days it describes.

Unusual use: demand signals by state for stocking

A dealer group buying for stores in several states wants to know which models are climbing in each state before its own lots show it. The rankings change monthly, so save each month's list and compare it with the last one.

  1. Monthly
  2. State rankings, new and used
  3. Compare with last month
  4. Your lot counts from the DMS
  5. Buyer adjusts the plan
rank_moves.pypython
import json
import os
from pathlib import Path

import requests

BASE = "https://api.marketcheck.com/v2"
KEY = os.environ["MARKETCHECK_API_KEY"]

def ranking(state, car_type):
    r = requests.get(f"{BASE}/popular/cars", timeout=60,
                     params={"api_key": KEY, "car_type": car_type, "state": state})
    r.raise_for_status()
    return {f'{c["make"]}|{c["model"]}': {"rank": i + 1, "count": c["count"],
                                          "dom_median": (c.get("dom_stats") or {}).get("median")}
            for i, c in enumerate(r.json())}

def moves(state, car_type, folder=Path("popular-snapshots")):
    folder.mkdir(exist_ok=True)
    path = folder / f"{state}-{car_type}.json"
    last = json.loads(path.read_text()) if path.exists() else {}
    now = ranking(state, car_type)
    path.write_text(json.dumps(now))
    rows = [{"model": key.replace("|", " "), **cur,
             # positive = climbing; None on the first run or for a model new to the list
             "change": last[key]["rank"] - cur["rank"] if key in last else None,
             "new_to_list": bool(last) and key not in last}
            for key, cur in now.items()]
    dropped = [key.replace("|", " ") for key in last if key not in now]
    return sorted(rows, key=lambda row: row["change"] or 0, reverse=True), dropped

Join the output to your DMS counts by make and model, and the buyer gets four columns per state: the rank, the move since last month, the median days on market and the units on your lots. A model near the top of the list with a short median days on market sells in volume and turns quickly. The buyer's first look goes to models climbing in a state where the group holds few units.

Run the same comparison across states to spot a model that ranks higher next door than in your own market. Because the ranking stops at make and model, check trim-level turn with the Market Days Supply or Inferred Sales Stats endpoints before a big buy.

Unusual use: an SEO content calendar from what people buy

Publishers and dealer marketing teams plan buyer's guides, comparisons, model pages and local landing pages. The rankings say which models people in each market are buying, so the calendar can follow them.

  1. State and city rankings
  2. Models without a page yet
  3. Editor schedules posts
  4. Pages refreshed monthly

Take the state and city lists for the markets you target and remove the models you already cover in your CMS. What remains, in rank order, is the backlog. The moves() output above sets the order within it: models new to a list and models climbing fast go first, and pages for models that dropped off can wait for a refresh. A publisher covering many states can also count how many state lists each model appears on, which separates national stories from local ones.

Because count measures sales, this calendar follows purchases. Pair it with your own search analytics if you also want to cover what people research before they buy.

Gotchas

  • car_type is required. A request without it returns a 400.
  • Send one location. city_state takes precedence over state, and the docs say to use one or the other.
  • The window is 90 days and the refresh is monthly. A rank change reflects three months of sales, so treat it as a slow signal and cache the lists between refreshes.
  • Match names before you join. make and model come back as MarketCheck names them (RAV4 in the sample), so normalize case and spelling before joining to your DMS or CMS.
  • Read each block's count. Price, mileage and days-on-market statistics each cover their own set of listings.
  • Canada is a separate list. Pass country=ca for Canadian rankings.

Who this is for

  • Dealer web and marketing teams adding popular-near-you widgets and state pages.
  • Buyers and inventory managers at dealer groups planning what to stock in each state.
  • Publishers and SEO teams building content calendars around what sells.
  • Car-shopping sites and apps that want a local "what people buy here" view.

Start here

  1. Create a free account and copy your API key. Start on the Free tier for development; plans are on the pricing page.
  2. Call /v2/popular/cars?car_type=used&state=<your state> and read the top of the list.
  3. Save that response and compare it with next month's before you build alerts on the changes.
  4. Put the city lists behind a cache before they go on a page.

The reference is the Popular Cars page in the MarketCheck docs.

Start building on the Free tier.

The Free tier is for development and testing, on the same endpoints you will use in production. When you go live, pick a plan on the pricing page.

More use cases

All use cases